Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question How to set up pixel perfect UI for mobile devices?

Discussion in '2D' started by GarbDev, May 11, 2020.

  1. GarbDev

    GarbDev

    Joined:
    May 1, 2016
    Posts:
    10
    I am working on a 2D pixel art game for mobile devices and am at an absolute loss as to how I should set up the UI. I am of course using the 2D Pixel Perfect package, but this does not seem to affect UI. I need to have UI elements that follow game objects, so I tried using World Space canvases. However, these cannot be set to pixel perfect, resulting in jittery movement since the game objects are set to pixel perfect. I then tried using a Screen Space canvas with the scaling mode set to Scale With Screen Size, and while this initially works, the UI elements do not scale properly when rotating the device between portrait and landscape. Finally, I tried setting the scaling mode to Constant Pixel Size, but the UI elements don't have the same ratio of pixels per unit as the game objects, despite matching values in the inspector.

    I really don't know how to proceed from here. I can think of a few custom scripts I could write to fix these issues, just as manually snapping UI elements to a grid or reading the device orientation to change the reference resolution, but I can't help feeling that these are extra steps and I am overlooking something. I would greatly appreciate any help with this issue.
     
    cassidyg likes this.
  2. RevengerWizard

    RevengerWizard

    Joined:
    Feb 15, 2020
    Posts:
    15
    Hi!
    I have the same problem. I've searched around and looks like there isn't a proper solution for this. I wanted to achive pixel perfect UI, without distortion. I tried to set the Canvas to Screen Space - Camera, on the camera having the pixel perfect component and the canvas scaler mode to Scale with Screen Size (pixel perfect camera resolution and canvas scaler resolution the same).
    Well, it kinda worked. However, this method distorts the images.
    If someone found a solution to achive pixel perfect UI, please reply.
     
    cassidyg and Eater_Games like this.
  3. GarbDev

    GarbDev

    Joined:
    May 1, 2016
    Posts:
    10
    I know this is a super late reply, but I wanted to post what I ended up doing for anybody who finds this thread. For snapping word space UI elements to a grid, I created a PixelSnapper script that gets a reference to the Pixel Perfect Camera component and performs the following in LateUpdate():
    Code (CSharp):
    1. // Check whether transform has changed
    2.         if (transform.hasChanged)
    3.         {
    4.             // Set target position
    5.             Vector2 targetPosition;
    6.             if (transform.parent != null)
    7.                 targetPosition = (Vector2)transform.parent.position + (Vector2)pixelPerfectCamera.RoundToPixel(transform.localPosition);
    8.             else
    9.                 targetPosition = transform.position;
    10.  
    11.             // Snap to pixel grid
    12.             transform.position = pixelPerfectCamera.RoundToPixel(targetPosition);
    13.             transform.hasChanged = false;
    14.         }
    Then, to dynamically change the scale based on the orientation, I created a PixelPerfectCanvasScaler script that inherits from UIBehaviour, allowing for OnRectTransformDimensionsChanged to be defined. That script gets a reference to the Pixel Perfect Camera component and the Canvas Scaler component and performs the following:
    Code (CSharp):
    1. // OnRectTransformDimensionsChange is called when an associated RectTransform has its dimensions changed.
    2.     protected override void OnRectTransformDimensionsChange()
    3.     {
    4.         if (gameObject.activeInHierarchy)
    5.             StartCoroutine(SetScaleFactorAtEndOfFrame());
    6.     }
    7.  
    8.     // Call SetScaleFactor at end of frame
    9.     IEnumerator SetScaleFactorAtEndOfFrame()
    10.     {
    11.         yield return new WaitForEndOfFrame();
    12.         SetScaleFactor();
    13.     }
    14.  
    15.     // Set the canvas scale factor to match the pixel perfect canvas
    16.     void SetScaleFactor()
    17.     {
    18.         canvasScaler.scaleFactor = pixelPerfectCamera.pixelRatio;
    19.     }
     
    RevengerWizard likes this.
  4. RevengerWizard

    RevengerWizard

    Joined:
    Feb 15, 2020
    Posts:
    15
    How to access the UIBehaviour? It doesn't exist

    Also, I tried the code and it doesn't work (I'm using the ScreenSpace - Camera). The UI images of the Canvas are just thrown away.
     
    Last edited: Feb 9, 2021
  5. RevengerWizard

    RevengerWizard

    Joined:
    Feb 15, 2020
    Posts:
    15
    Nevermind, now works, but still it vibrates when I move.
     
  6. GarbDev

    GarbDev

    Joined:
    May 1, 2016
    Posts:
    10
    You need to use the EventSystems namespace.
    Code (CSharp):
    1. using UnityEngine.EventSystems;
    What vibrates? The camera or the UI?
     
  7. RevengerWizard

    RevengerWizard

    Joined:
    Feb 15, 2020
    Posts:
    15
    The UI. Just to test I attached the Camera to the Player GameObject and tested a bit. When moving, the UI vibrates.
     
  8. GarbDev

    GarbDev

    Joined:
    May 1, 2016
    Posts:
    10
    Is the UI in screen space or world space? I've only tested the PixelSnapper script with world space UI objects.
     
  9. RevengerWizard

    RevengerWizard

    Joined:
    Feb 15, 2020
    Posts:
    15
    The UI is Screen Space, so I think it's beacuse of that.