GameMaker How Do I Avoid Subpixel Rendering?

M

Melbo

Guest
I'm trying to make a pixel art game but my objects move in sub pixels. They don't stick to the pixel grid, and you can see they shift into half pixels.

I have my Camera Properties set to 398x224, and the Viewport Properties set to 1280x720. So they're both rendering at the same aspect ratio, 16:9. I thought this would fix the problem but it doesn't.

Can anyone help?
 

Attachments

poliver

Member
round() floor() or ceil() your objects x and y at the end of the step event and do the same thing with the camera coordinates

that's not the best way but simplest
 

NightFrost

Member
Yeah not the best way as that'll make the movement speed jitter a bit. Which may or may not matter to OP. Better to do the rounding in the draw command instead. I'd also recommend rounding over floor or ceil, as collision commands naturally round positions before running the checks. If you floor or ceil instead, there'll at times be 1-pixel disrepancies between collisions and draw position. Which may or may not be a bother (or avoided by also using floor or ceil when injecting stuff into the collision checks).

Also, those sizes don't seem to be at integer multipliers with each other, so don't expect evenly sized pixels at every point if you start measuring them from a screenshot.
 
M

Melbo

Guest
Thank you for the replies. I'm pretty new to this, so I haven't heard of these commands before.
If I round the x and y, would I do it like this?
round(x += hsp);

And if I did it in the draw command, where would I use it?
Something like this?
draw_sprite_ext(o_player, 0, round(x), round(y), 1, 1, 0, image_blend, image_alpha);
 

TheouAegis

Member
If I round the x and y, would I do it like this?
round(x += hsp);
Pretty sure in GM it has to be

x=round(x+hsp);

But you wouldn't want that line of code anyway. If x is 4 and hsp is 0.2, then x would always be 4. If hsp is 0.6, then x would go up by 1 every step (which is hsp of 1, not 0.6).

Another thing to keep in mind is if you are merely rounding the sprite's coordinates when it is drawn, then you need to physically round off the view's coordinates as well, if you use views.

If the player is at 130.3 and you have a view of size 256 following the player centered on the player, then the view would be at 2.3. Even if GM automatically handles rounding off the view, you'd still end up with erratic sprite positioning throughout the project.

It's as big a headache as it sounds.
 
G

Gift of Death

Guest
Another note worthy thing to keep in mind is the size of the application_surface.

Here's a demonstration of how a rotating sprite looks on how the app surface is scaled by default and if the app surface is the same size as the view in room, drawn scaled up to fit the viewport:


Basically, default app surface scaling sets the size to fit the viewport and everything drawn onto it are scaled up, allowing subpixel movement and rotation. The way to stop that from happening would be running this on game start:
Code:
// You can just replace the camera functions with the view size numbers if you'd like, or whatever fits your system
surface_resize( application_surface, camera_get_view_width( view_camera[0] ), camera_get_view_height( view_camera[0] ) );
 
Top