Pixel rounded position rendering for zoom option

I’d like an option to the camera layer zoom that allows the view to be the same as a 1x zoom, except just simply larger.

Currently, when using the camera layer zoom, things enlarge in such a way that you can see the sub pixel positions of objects, however this would ruin games that are meant to be pixel perfect.

If possible, the way to trigger this could just be a checkbox in the existing camera zoom option.

The reason I want this feature, besides fixing the problem already mentioned, is so that:

  1. Pixel perfect games can be created with the correct pixel grid while allowing HD assets on top of, or around the games. Currently, using HD assets would sacrifice the pixel grid.

  2. Being able to use anti-aliasing, without making it look blurry, by using high resolution and zoom. And again not having to sacrifice the pixel grid which is what would currently happen. An example of this problem can be seen here:
    Platformer with tilemap - a game example from the GDevelop game making app | GDevelop

This is exactly what I want to avoid:

The character’s pixels are rendered in between other pixels, which is happening because the camera is zoomed in. This is because it’s displaying the decimal value for the position, which at that moment looked like this:


And this is what I hope it would look like with the feature I’m requesting, even at decimal values (and during motion):



To clarify, for the most part this is a solved item via existing functions in the engine along with ensuring you are setting up your zoom and events corrextly.

Pixel perfect zoom is only mathematically possible if you are zooming at integer scales (2x, 3x, etc). Any zoom done at non-integers (1.25x, 2.5x, etc) will always have subpixels or other adjustments because you are trying to make 1 pixel into 1.25 pixels. Thats just how the math works.

As far as subpixel movement, there is a project setting called pixel rounding ehich will round all positions of objects/movement/camera positions/etc.

You would want to combine using this setting along with only zooming at integer scales, and you will avoid subpixel rendering.

( so long as you aren’t doing something odd like having a non-integer scale from your game resolution to your monitor resolution when you fullscreen. e.g. your game project is set to 720p but your monitor is 1080p, which is 1.5x larger. You will always have subpixel rendering if you fullscreen the game due to this.)

No… sorry, none of that is what I mean :frowning:
I worded it wrong, I just don’t know what the word is. The problem is not with non integer zooming, which as you say for example 1.5 would have uneven pixels. That’s not what this is about.

I’m probably going to have to upload gifs to explain this :joy: be back in a little bit

To clarify, I follow what you mean.

You are displaying subpixel rendering. Subpixel rendering and graphical distortion both have to do with movement along with zoom, as I mentioned above. If you’re wanting “pixel grid” movement, you need to either:

A. Keep your game at native resolution, not zoom in at all, let the nearest neighbor scaling do it on it’s own. This still means your game resolution must be an exact integer of the game display, 320x180, 640x360, etc. No 1280x720 game resolution if you have a 1080p or 4k display. - I don’t recommend this, because you’ll have “jittery/stuttery” movement, which is true to old school consoles (since they were actually at the low resolutions), but most modern game players aren’t connected with that and will complain.


B. Zoom in with a higher resolution, but turn on pixel rounding in your project settings, and make sure you are rounding your positions if you do any position changes. - I recommend this as it is more commonly how modern games with a retro pixel aesthetic work.

Here’s an example:

Updated project settings:

Updated event:

You can then fullscreen with f11 and it’ll look like this and movement will be fluid.

Ah yes this is much more like what I meant, where you say “and make sure you are rounding your positions if you do any position changes”.
I did in fact attempt this! But it broke any conditions or movements that relied on decimals. For example, if I needed to move a character only 0.2 pixels per frame to simulate a slow speed, my event that was rounding the positions made it impossible for the character to move since 0.2 is not enough to round up to the next pixel for example.

Then, I came up with an even crazier idea (that I have not tested yet as I just came up with it), maybe my only solution with the way things currently work, is to have an invisible object with all its decimals calculated properly, and a visible object on top with the rounded values calculated. I am dreading this though :frowning: I might have to do it for now, but I really would love if this could just be implemented in GDevelop with just an option in the camera zoom action.

Anyway, so I’ve prepared 2 little videos anyway while I was gone, though it will not be necessary now that I see the problem is understood :smiley: but it’s already made so I’ll upload here:

This is how it looks when there’s camera zoom being used:

And this is how I wish it actually looked after zoom with a new option:

For the latter, you want true “retro” movement, upon which you have no real benefits of doing zooming on your layers.

Which means you can just run your project at 320x160 (or whatever resolution is closest to your desired asset size) and turn on nearest neighbor scaling and it’ll have the style of movement you want. Just ensure you have the ‘adjust resolution’ checkbox disabled in your project property settings, and you’ll have that style of movement when you fullscreen.

Again, note that some players will see this as “wrong” even though you are actually being true to how games worked back on the NES and such.

Otherwise, if you absolutely must have zooming, then yes, you can have a hidden player object (usually referred to on the forums as a hitbox object) and then just have a visual sprite object that is set to the hitbox object’s X and Y, but with the positions rounded.

“Upon which you have no real benefits”
What about HD assets outside the game screen? :smiley:
Or on top of it… or maybe even a mixture haha. Like say, a game that has pure retro pixel movement, like an RPG, but when the characters talk and their portraits show, it’s HD, or maybe the fonts.

I played a game the other day that was from a game jam, where it starts 2D, but the player could put the screen down and reveal a 3D world. (sorry for the spoiler)
I’d want something like this, except the 3D would be HD and the low res game would be pure retro pixel with the correct movement.

“some players will see this as “wrong” even though you are actually being true to how games worked back on the NES and such”

Hahaha, yeah, I want it to be like how it worked back on the NES and the other old consoles! I didn’t know that invisible object was referred to as a “hitbox object”. Maybe the camera can have an option called “Pixel rounded rendering” so no one has to go the extra miles for this? :pleading_face:

(I’ll try to update my post title to avoid others confusing it with the non integer zoom)

Update: Yup, definitely the camera zoom could use this feature.
As I work on my game create an object that displays on the pixel rounded positions of an invisible object, I’ve found quite a few challenges, like collisions. Sometimes they don’t calculate properly for the graphic object, requiring more work to be put into this, while also still having a slightly more jittery result than without this whole process.

You might also try the pixel perfect movement extension to simplify some of the movement.

However, there shouldn’t be any real collision issues, because with your zoom there should only be a difference of under 1 pixel. Unless you’re doing something odd, it should just be using the Position object action (targeting your sprite) and have it use round(HitboxObject.X()) and round(HitboxObject.Y()).

Or if you want it to be an exact 1:1 match for “1 pixel = Zoom*Pixel movement”, you’d just do a slightly more advanced calculation.


So in your very first screenshot, it’d end up being (round(79.333666000002/6)*6) or 78.

It’ll be slightly closer than just doing round(79.333666~) in some very specific scenarios.

You know, for the most part, I’m doing well with the round function, but I didnt understand the /6*6 part (or current zoom factor number). Doesn’t that just result in the same number?

Btw, there’s an action giving me problems :sweat_smile: it’s the “Separate objects”. It’s the only thing I know of to make walls for top down characters. It makes the position values act a bit strange and produce lots of decimals. Is there a more proper way to make collisions for top-down characters?

No, you’ll get very different numbers if you just round the current X position. You can try it out with some pretty simple tests.

If you’re zooming in by 5x (meaning 5 pixels zoomed in = 1 pixel unzoomed), and your character is at X 48.3. Rounding X would just make you go to 48.

Instead, If you first 48.3/5 is 9.66. Rounding that result brings you to 10. 10*5 = 50, which is actually the “correct” rounding for the position if you were moving 1 pixel to the next “real” position (*5).