CanvasLayer and a 2d camera with 8x zoom

Godot Version

v4.5.1.stable.official [f62fdbde1]

Question

Hey all,

I am working on a 2D pixel art game with the following setup:

  • 1920x1080 window size
  • Camera2D with 8x zoom

This setup works great. The zoom makes the pixel-art pixels big and readable, and the large window size gives smooth sub-pixel scrolling.

The challenge is positioning UI nodes, for example a Label anchored to the top-right corner. Since CanvasLayer is not affected by the camera zoom, it assumes a much larger viewport than what is visible through the camera. That makes UI layout in the editor awkward because the UI elements end up far away from the gameplay area (plus the scale is off).

Is there a clean way to handle this?

Editor view: notice the Label is far outside the visible camera area.

Game view: the Label appears in the correct top-right position.

Sample project demonstrating the issue:

Looks right to me. You are not viewing the UI through the camera so naturally it shouldn’t be affected by its zoom (or pan or rotation).
Normally you would edit the UI in a separate scene. Then you can drop a 1920x1080 screenshot of the game (or a layout scheme) behind the UI and use that as a visual reference.

That’s very normal and how it should work. Usually most UI elements should always have the same scale and position, independently from your camera zoom/position settings.

The blue (indigo colored) rect is your default viewport window boundaries. So your UI window is basically that. And you can see that the anchors are at the top right of the default viewport recntangle. So it means that label will always be around that position. You need to check anchor points & offset settings to configure exactly how you want.

Thank you @rpahut and @lastbender for a quick reply!

Actually, I’ve considered the screenshot of the game to help me design the UI layout. While I am likely to go this route, it still feels more like a work-around than a proper solution.

Assuming this is as good as it gets today, I believe it could be improved in a future Godot release. I think there are a few ways this could be done (from the :

  1. Add a new property directly to the Project Settings -> Window section, e.g. Viewport Zoom. This would work same way as the camera zoom but it would also affect the CanvasLayer.
    Note the relatively high resolution Viewport Width/Height combined with Viewport Zoom > 1 still makes sense, since they produce large pixels that can be scrolled smoothly using a device’s physical resolution.

  2. Have the viewport adapt it’s size based on the closest camera zoom settings (per docs Camera2D will always display on the closest parent Viewport). The actual viewport would be properly shown in the editor (the blue/indigo rectangle) and all CanvasLayer nodes would be rendered in the correct places.
    This seems like the best solution to me. However, I’m not aware of all the implications of such a change, so maybe it would break a lot of stuff?

  3. Add zoom property to the CanvasLayer so that setting it to the same value as the camera zoom would fix the problem.
    This seems like a quick fix/hack to solve the problem. Not perfect, but still better than the current state of things.

Does any of this make sense? Is it worth filing a GH issue for such an enhancement?
Thanks!

You can change the viewport size to match your zoomed world size. It may give you a better world view / ui view match that you are looking for

I tried that. It works great for the world view/UI to match. However to have my game rendered full screen I need to set the Window -> Stretch -> Mode to the viewport as this is the recommended setting for pixel art games. The downside is that with such a setup the camera panning is noticeably jerky when it is moved slowly by the stretched pixel by stretched pixel…

I’ve just noticed this issue goes away when I change the Window -> Stretch -> Mode to the canvas_items! The scrolling is smooth and the world view/UI matches as expected! I’ve also just found this note in the documentation:

The viewport stretch mode provides low-resolution rendering that is then stretched to the final window size. If you are OK with sprites being able to move or rotate in “sub-pixel” positions or wish to have a high resolution 3D viewport, you should use the canvas_items stretch mode instead of the viewport stretch mode.

I am a bit confused: so is the canvas_items stretch mode a good choice for a pixel art game? Any downsides I should be aware of?

If what you are making is a 240x135 game then Viewport mode is the correct recommendation. It’s not “jerky”, it’s that there are only 240 distinct positions per screen horizontally. But you are free to have an HD game with blocky low resolution sprites instead if that aligns with your vision better. There is some overhead in rendering a larger game image but any real device will handle that just fine.

Just for fun, and to help others who are new to Godot, here’s a short video that demonstrates a display/window/stretch/mode set to viewport vs. canvas_items.

Other key settings:

  • display/window/size/viewport_width = 240
  • display/window/size/viewport_height = 135
  • display/window/stretch/scale_mode = integer
  • camera/position_smoothing_speed = 5.0 px/s
  • camera/zoom = 1.0