Scaling up my game 4x without resizing a single sprite (GM:S 1.4)
This post is outdated
This post strictly refers to GM:S 1.4 and not GameMaker Studio 2. I also do not recommend doing this upscaling; using surfaces, you might be able to keep very low resolution asset, while still being able to draw smooth movement with subpixel precision.
For more info: Guide to develop low resolution 2D platformers with smooth movement and pixel perfect collisions in GameMaker Studio 2 (with slopes)
So I was developing a low res game (480 x 270) in GameMaker: Studio 1.4. The moment comes when I need to test it on mobile. I create my APK, load it up on the phone and there it is… a horrible mess of graphic artifacts!
The camera movement was all jittery, the zoom effect made all the tiles look funny and overall it just felt wrong.
The problem was obviously the very low resolution of the game. The camera (the view), along with every other object in the game, can move only by whole “game pixels”. That means that if you divide the actual display resolution by the game resolution (480 horizontal pixels in my case) you get the minimum “screen pixels” that any object can be moved/re-drawn. No in-between values are possible.
On a 1920 pixels wide screen, that’s 4 “screen pixels” per “game pixel”. So the camera (along with every other objects) can move only by 4 screen pixels at once and no less. This means jittery movement.
Since I wanted the camera to be able to move at least 1/4th of a game pixel, I had to upscale the whole game by a factor of 4… I had to go Full HD to keep my low res game enjoyable.
That meant resizing 175 sprites, move their origins, check their collision masks, resize the tilesets and backgrounds, adjust the speeds, re-make the whole levels and probably fix other bugs… unless…
Unless I used this code in the room start event of my controller.
global.game_scale = 4 // Increase the room size room_width = room_width * global.game_scale room_height = room_height * global.game_scale // Object resize with(all) { x = x * global.game_scale y = y * global.game_scale image_xscale = image_xscale * global.game_scale image_yscale = image_yscale * global.game_scale } // Tile resize var num = tile_get_count(); for (var i = 0; i < num; i++;) { var tid = tile_get_id(i) var tx = tile_get_x(tid) var txs = tile_get_xscale(tid) var ty = tile_get_y(tid) var tys = tile_get_yscale(tid) tile_set_scale(tid, global.game_scale, global.game_scale) tile_set_position(tid, tx * global.game_scale, ty * global.game_scale) }
I also increased the view size by 4 (and resized the application surface accordingly) so the objects in the game looked exactly like before (size-wise). Now everything is 4 times bigger.
View and Application Surface
My application surface (and the view) have a 1080 pixels vertical resolution. The horizontal resolution is dynamically calculated based on the monitor aspect ratio. The application surface is then manually drawn stretched to the display in the post-draw event (i.e. this game looks just as good on a 4:3 monitor than it does on a 16:9 one).
I still have to resize any in-game created instance and modify the speeds of some of my objects… but at least I didn’t have to resize 175 sprites. Now the camera moves and zooms smoothly. Everything can move 1/4th of a game pixel without looking jittery.
Hello. Thank you so mutch for a nice tutorial. I think i do something wrong. Maybe you coud help me?
I tried to put this in but i just got this error message. Coud you be a bit more specific please.
Object: oPlayer Event: Game Start at line 29 : unknown function or script tile_set_position
Object: oPlayer Event: Game Start at line 22 : unknown function or script tile_get_id
Object: oPlayer Event: Game Start at line 23 : unknown function or script tile_get_x
Object: oPlayer Event: Game Start at line 24 : unknown function or script tile_get_xscale
Object: oPlayer Event: Game Start at line 25 : unknown function or script tile_get_y
Object: oPlayer Event: Game Start at line 26 : unknown function or script tile_get_yscale
Object: oPlayer Event: Game Start at line 28 : unknown function or script tile_set_scale
Object: oPlayer Event: Game Start at line 19 : unknown function or script tile_get_count
Thanks for stopping by. It looks like you’re using GameMaker Studio 2. This post is (was?) valid for GameMaker Studio 1.x only. Tiles manipulation in GameMaker Studio 2 is fundamentally different as it now uses “real” Tilesets and Tiles Layers. The functions I use in this post have been removed and I still haven’t had time to research a way to achieve similar results in GMS 2. If I come across a conceptually similar solution, I’ll write about it.