Forum rules - please read before posting.

Hotspot icon scale is different on different devices

My game, when played on windows, Mac or steam deck, has the hotspot icons in wildly different sizes. It looks as its the icon pixel count is the same regardless of the device, so on mag retina and PC full HD and the smaller steam deck the icons are scaled very differently. On Mac they are very small, on the PC they are larger and on the deck they are game breakingly humongous.

The hotspot UI I have is the custom solution you Chris) sent me a while back in order to have the icons rendered trough unity UI in order to have the gamma display correctly on the Mac.

«1

Comments

  • The hotspot UI I have is the custom solution you Chris

    Is this a custom script? You'll need to refresh my memory, if so.

    If you're using Unity UI, the scaling will be dependent on the Canvas Scaler component. Can you share screenshots showing the setup?

  • Sure I can! Just a sec..

  • here is the setup for the canvas, but I think the scaling issues come from the hotspot script. I can refresh your memory on that as well.

  • `using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    using AC;

    public class HotspotIconsUI : MonoBehaviour
    {

    public Image iconToDuplicate;
    public CanvasScaler canvasScaler;
    private Dictionary<Hotspot, Image> hotspotIconDict = new Dictionary<Hotspot, Image>();
    private Sprite _defaultSprite;
    private Sprite _hoverSprite;
    private Hotspot _hoverSpot;
    private bool itemMode = false;
    private bool hovering = false;
    
    private void Awake()
    {
        Hotspot[] hotspots = Object.FindObjectsOfType<Hotspot>();
        foreach (Hotspot hotspot in hotspots)
        {
            if (hotspot.highlight == null) continue;
    
            Image icon = Instantiate(iconToDuplicate.gameObject).GetComponent<Image>();
            icon.transform.SetParent(iconToDuplicate.transform.parent);
            icon.gameObject.name += "_" + hotspot.name;
            hotspotIconDict.Add(hotspot, icon);
        }
        _defaultSprite = KickStarter.cursorManager.GetCursorIconFromID(9).GetSprite();
    }
    
    void OnEnable()
    {
        EventManager.OnHotspotSelect += hotHover;
        EventManager.OnHotspotDeselect += hotLeave;
        EventManager.OnInventoryDeselect += itemDrop;
        EventManager.OnInventorySelect += itemSelect;
    }
    
    void OnDisable()
    {
        EventManager.OnHotspotSelect -= hotHover;
        EventManager.OnHotspotDeselect -= hotLeave;
        EventManager.OnInventoryDeselect -= itemDrop;
        EventManager.OnInventorySelect -= itemSelect;
    }
    
    void hotHover(Hotspot hotspot)
    {
        //mark hotpsot for hover for rendering interaction icon
        hovering = true;
        _hoverSpot = hotspot;
    }
    
    void hotLeave(Hotspot hotspot)
    {
        //deselect hotspot for denreding hover icon.
        hovering = false;
    }
    
    void itemSelect(InvItem invItem)
    {
        itemMode = true;
    }
    
    void itemDrop(InvItem invItem)
    {
        itemMode = false;
    }
    
    private void LateUpdate()
    
    {
        foreach (Hotspot hotspot in hotspotIconDict.Keys)
        {
            Image icon = hotspotIconDict[hotspot];
            icon.color = new Color(icon.color.r, icon.color.g, icon.color.b, hotspot.highlight.GetHighlightAlpha());
    
            //Check if the icon is for an exit
            if (hotspot.GetFirstUseIcon() == 3)
            {
                icon.sprite = hotspot.GetMainIcon().GetAnimatedSprite(true);
            }
            else
            {
                //change the icon for the hotspot the mouse is hovering on
                if (hotspot == _hoverSpot && hovering == true)
                {
                    if (itemMode == true)
                    {
                        icon.sprite = KickStarter.cursorManager.GetCursorIconFromID(0).GetSprite();
                    }
                    else
                    {
                        icon.sprite = hotspot.GetMainIcon().GetAnimatedSprite(true);
                    }
                }
                //Use the default icon
                else
                {
                    icon.sprite = _defaultSprite;
                }
            }
    
            Vector2 screenPos = hotspot.GetIconScreenPosition();
    
            float scalerOffset = 1f;
    
            if (canvasScaler && canvasScaler.enabled && canvasScaler.uiScaleMode == CanvasScaler.ScaleMode.ScaleWithScreenSize)
            {
                switch (canvasScaler.screenMatchMode)
                {
                    case CanvasScaler.ScreenMatchMode.MatchWidthOrHeight:
                        float match = canvasScaler.matchWidthOrHeight;
                        scalerOffset = (ACScreen.width / canvasScaler.referenceResolution.x) * (1 - match) + (ACScreen.height / canvasScaler.referenceResolution.y) * match;
                        break;
    
                    case CanvasScaler.ScreenMatchMode.Expand:
                        scalerOffset = Mathf.Min(ACScreen.width / canvasScaler.referenceResolution.x, ACScreen.height / canvasScaler.referenceResolution.y);
                        break;
    
                    case CanvasScaler.ScreenMatchMode.Shrink:
                        scalerOffset = Mathf.Max(ACScreen.width / canvasScaler.referenceResolution.x, ACScreen.height / canvasScaler.referenceResolution.y);
                        break;
                }
            }
    
            Rect safeScreenRect = ACScreen.safeArea;
            Vector2 diff = new Vector2(ACScreen.width, ACScreen.height) - safeScreenRect.position - safeScreenRect.position - safeScreenRect.size;
            screenPos += diff / 2f;
    
            Vector3 localTargetPositionUI = new Vector3((screenPos.x - (ACScreen.width / 2f)) / scalerOffset, (screenPos.y - (ACScreen.height / 2f)) / scalerOffset, icon.rectTransform.transform.localPosition.z);
    
            icon.rectTransform.localPosition = localTargetPositionUI;
        }
    }
    

    }`

  • that's the code for it

  • The script doesn't affect the size of the icon - only its size and position is controlled by it.

    You should be able to recreate the behaviour by setting the Game window's resolution to different values, with and without the script. It may be that a different UI Scale Mode, such as Constant Physical Size, is best here.

  • The thing that I wonder is that the Ui canvas settings are the same for all of the game UI, but the only elements that scale incorrectly are the hotspot icons, so it must have something to do with the script. I can not think of anything else. Just to get an idea of the root cause of the issue would be amazing. What is also weird that changing the resolution in unity editor does nothing. The issue only appears in the build game. I wonder what is going on

  • it must have something to do with the script.

    You can check this by disabling the script component - it won't reposition or change the icon, but what happens to the size?

    Though, your screenshot suggests you might have multiple Canvas / Canvas Scaler components involved - do both your HotspotUI and Canvas objects have these? Generally, you should have one set of these per-hierarchy chain.

  • oh the "other" canvas is just a transform. It is a very hard bug to figure out as I can not replicate the scaling issue by resizing the play window in unity. it only happens on different hardware: Mac retina / pc screen / steam deck.

  • it seems to have to do with the DPI, which suggests to me that something is being scaled in absolute pixels instead of relative to the screen size. And I am not finding it easily.

  • Have you tried disabling the script component, to double-check if it's contributing?

  • I will do that.

  • Yes, it is the script. Here is a screenshot with a copy of the same canvas with and without the script enabled. (enabled on the right side)

  • the one with the script (right) is in absolute pixel size, the one without the script is relative to the screen size (left).

  • the changes are very slight when played on any computer, but low resolution devices like the steam deck have MASSIVE hotspot icons that are in the ballpark of half a character size.

  • Odd that this is a build-only issue - I can't rule out this being an issue with Unity itself, given that. This even doesn't occur when testing with "Free Aspect" and manually resizingt the Game window?

    As your script duplicates the "Image" object on startup, I assume the original is hidden / assigned an empty sprite. Test out showing this at runtime with a typical icon that normally shows, so that it can be compared with the duplicates - is this affected as well, or only the Images that you're duplicating and parenting to its same parent?

    Let's see the results of also:

    • Commenting out the assignment of the localPosition in the LateUpdate loop
    • Switching to "Constant Physical Size" in the Canvas Scaler
  • Thanks, I will try all of these! I am just in the process of adding options for accessibility for the hotspots and for text scale etc. I am such a fan of how good the Adventure Creator API is for modifying everything without touching the source! Great job!

  • Setting the UI to physical size made the hotspots look massive in Unity editor and play mode, but in build (on the Mac) the hotspots controlled by the code were scaled the same as the baseline image without code controlling it's position. I also commented out the local position but then the hotspots were not visible on screen at all.

  • I will experiment more with the physical size to see what it means.

  • Everything completely broke down after I trued different resolutions with the build game. When the physical size was on, the baseline hotspot was absolutely massive and the other hotspots were located in wrong places around the game screen.

Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Welcome to the official forum for Adventure Creator.