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.
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.
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():
// Check whether transform has changed
if (transform.hasChanged)
{
// Set target position
Vector2 targetPosition;
if (transform.parent != null)
targetPosition = (Vector2)transform.parent.position + (Vector2)pixelPerfectCamera.RoundToPixel(transform.localPosition);
else
targetPosition = transform.position;
// Snap to pixel grid
transform.position = pixelPerfectCamera.RoundToPixel(targetPosition);
transform.hasChanged = false;
}
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:
// OnRectTransformDimensionsChange is called when an associated RectTransform has its dimensions changed.
protected override void OnRectTransformDimensionsChange()
{
if (gameObject.activeInHierarchy)
StartCoroutine(SetScaleFactorAtEndOfFrame());
}
// Call SetScaleFactor at end of frame
IEnumerator SetScaleFactorAtEndOfFrame()
{
yield return new WaitForEndOfFrame();
SetScaleFactor();
}
// Set the canvas scale factor to match the pixel perfect canvas
void SetScaleFactor()
{
canvasScaler.scaleFactor = pixelPerfectCamera.pixelRatio;
}