Scaling, Resolution, and Aspect Ratio Management for GMS1 & GMS2

I

IndieRex

Guest
Great tutorial! I am having one issue though. For some reason it is drawing a black bar at the top of screen, but doesn't do it if I comment out the pixel perfect portion of the script.

I'm using the GMS 2 version of the tutorial, have checked the code multiple times, but can't seem to figure out what might be causing it. My ideal height is set to 540 with my room sizes at 960x540.
 
I

IndieRex

Guest
@IndieRex
I don't recommend using the pixel perfect scaling... but that said, it certainly shouldn't give you black bars. What's the resolution of your monitor?
1920x1200. There is only one bar at the top of the screen (rather than one at bottom and top). Not sure why turning it off is fixing it either.

I'll keep it turned off then!
 
@IndieRex

Ah, because your room isn't tall enough! When you scale it to be pixel perfect, it will scale the height to be perfect. 540 doesn't go perfectly into 1200, so it resizes your view to be 600 tall. Your rooms are only 540 tall, so you see the outside of your room, which is black.
 
I

IndieRex

Guest
@IndieRex

Ah, because your room isn't tall enough! When you scale it to be pixel perfect, it will scale the height to be perfect. 540 doesn't go perfectly into 1200, so it resizes your view to be 600 tall. Your rooms are only 540 tall, so you see the outside of your room, which is black.
Ah that makes sense! Thanks again for your help. Great series - really appreciated the lead-up videos explaining the background of the topic and laying the groundwork for the system.
 
I

IndieRex

Guest
Sorry for another question so soon, but I'm now having an issue where the text I draw is getting distorted (I think only in fullscreen mode). I did a check and my camera width/height are running at 864x540.

My rooms are 960x540, my ideal height is set to 540, and my computer resolution is 1920x1200.
 
Are you drawing your text in a gui event? When you are in full screen, do you have black bars at the top and bottom (you shouldn't)?
 
@IndieRex
So, the only time there should ever be distortion is when aspect ratios don't match. Specifically your view and your application surface. Here's a script I use to debug all this.

https://www.dropbox.com/s/tupyzjlwk9fz7sr/display_write_specs_GMS2.gml?dl=0
https://www.dropbox.com/s/wnvl0ok047w1d95/display_write_all_specs_GMS2.gml?dl=0

Add those two scripts to your project, and then in your draw_gui event somewhere write:
Code:
display_write_all_specs_GMS2(5,5);
The numbers in the parentheses is your aspect ratio for that element. All of those numbers should be the same. If not, there's a chance for distortion. So that should give you an idea where to look. If you still can't figure it out, send me a screenshot, and I'll be happy to help you.

Also, just FYI, you can join my Discord server where hundreds of awesome GM developers hang out and help each other. It's a great way to get programming help without the waiting for forum post responses, and I'm there 5 days a week along with many very skilled and helpful developers. https://discord.gg/sehNsp
 
I

IndieRex

Guest
@Pixelated_Pope

Thank you for the scripts. I ran it, but it looks like they are all the same number. Here is a screenshot showing it. The issue is also definitely not the font either as when I run the game without the scaling system it looks great. I'm on the discord as well too!
 

Attachments

@IndieRex That is indeed weird. The only thing I can really think of is that there is some sort of pixel interpolation going on. Do you have that setting turned on? Even then, it looks weird. If you'd be willing, you could PM me your project and I'll see if I can figure out what's going on.
 
T

TylerMcDe

Guest
This tutorial is the gift that keeps on giving for years now lol.
 
R

rouzbeh78

Guest
Hi
I saw all videos and do whatever you said
my orginal view must be like this :
but in my phone i get this result:



why is that ??
this is my obj_display_manager:
CREATE:

ideal_width=0;
ideal_height=720;
zoom=1;
max_zooom=1;
display_width=display_get_width();
display_height=display_get_height();

aspect_ratio=display_width/display_height;
//aspect_ratio=clamp(aspect_ratio, 1280/720, 1280/720);

ideal_width=round(ideal_height*aspect_ratio);
//ideal_height=round(ideal_width / aspect_ratio);

//Perfect Pixel Scaling
if(display_width mod ideal_width != 0)
{
var d = round(display_width/ideal_width);
ideal_width=display_width/d;
}
if(display_height mod ideal_height != 0)
{
var d = round(display_height/ideal_height);
ideal_height=display_height/d;
}

//Check for odd numbers
if(ideal_width & 1)
ideal_width++;
if(ideal_height & 1)
ideal_height++;

//Calculate Max Zoom
max_zoom=floor(display_width/ideal_width);

for(var i=1; i<=room_last; i++)
{
if(room_exists(i))
{
room_set_view(i,0,true,0,0,ideal_width,ideal_height,0,0,ideal_width,ideal_height,0,0,0,0,-1);
room_set_view_enabled(i,true);
}
}


window_set_size(ideal_width,ideal_height);
display_set_gui_size(ideal_width,ideal_height);
surface_resize(application_surface,ideal_width*zoom,ideal_height*zoom);

alarm[0]=1;

room_goto_next();

ALARM[0]

window_center();

unfortunately i used 1280x720 but I do not think this have anything to do with my problem
i also used GMS2 and saw Part 5 of your videos series but that couldn't help to
and also i don't need any view to follow my characters.
please somebody help me :(
 
Last edited by a moderator:
@rouzbeh78 Okay. First off, it looks like your game isn't pixel art based, so 720p is just fine :D.

So, remove the pixel perfect scaling portion of the code:
Code:
//Perfect Pixel Scaling
if(display_width mod ideal_width != 0)
{
var d = round(display_width/ideal_width);
ideal_width=display_width/d;
}
if(display_height mod ideal_height != 0)
{
var d = round(display_height/ideal_height);
ideal_height=display_height/d;
}
Remove all that. That alone may fix it for you depending on the resolution of your phone.

As for view following your characters, I discuss how to do that in my Part 5 video.
camera_view_set_pos(view_camera[0],player.x,player.y)
 
R

rouzbeh78

Guest
@rouzbeh78 Okay. First off, it looks like your game isn't pixel art based, so 720p is just fine :D.

So, remove the pixel perfect scaling portion of the code:
Code:
//Perfect Pixel Scaling
if(display_width mod ideal_width != 0)
{
var d = round(display_width/ideal_width);
ideal_width=display_width/d;
}
if(display_height mod ideal_height != 0)
{
var d = round(display_height/ideal_height);
ideal_height=display_height/d;
}
Remove all that. That alone may fix it for you depending on the resolution of your phone.

As for view following your characters, I discuss how to do that in my Part 5 video.
camera_view_set_pos(view_camera[0],player.x,player.y)
thank you so much that does the trick ! :)
 

w0rm

Member
Thanks for the great tutorial @Pixelated_Pope!!

The code works great also in GMS2. I wanted to separate the camera controlling code from the display manager object to its own. For a moment I had hard time playing with those global variables etc. Then by browsing docs I found a way to get completely rid of those by making the changes shown below. I decided to share this in case it's helping someone working with your great code.

Create event:

Replace

Code:
camera = camera_create();
globalvar view_x,view_y,view_w,view_h;
view_x = 0;
view_y = 0;
view_w = ideal_width;
view_h = ideal_height;
with

Code:
camera = camera_create_view(0, 0, ideal_width, ideal_height, 0, -1, -1, -1, 0, 0);
This allows using those new camera and view related functions which camera_create() apparently does not. Also setting of the view size in the End Step event is not necessary anymore. NOTE! The code used to show display specs needs updating as well...

After that it's easy to move and update the view positioning code from the End Step event to another object as below.

End Step event:

Replace with

Code:
var _view_w = camera_get_view_width(view_camera[0]);
var _view_h = camera_get_view_height(view_camera[0]);
var _view_x = instance_followed.x - _view_w / 2;
var _view_y = instance_followed.y - _view_h / 2;

var _round = _view_w / surface_get_width( application_surface );
camera_set_view_pos(view_camera[0], round_n( _view_x, _round ), round_n( _view_y, _round ) );
Of course one needs to set the instance to be followed in the Create event of this (or use object reference as in the original).
 
Ah, good adjustments, @w0rm!

At the time I was writing the tutorial, I believe camera_create_view was bugged and not working as expected, which is why I didn't use it at the time. Thanks for patching the tutorial for me :D
 

instaboy

Member
Hi! I followed your tutorial in the hope it would solve my issues with jittering graphics, but it didn't. The camera follows the character and he looks fine, but when the view moves it seems as if everything else is wildly virbrating. Just look at the eye of the sprite in the beginning. I snapped a quick video of it with my phone (couldn't get the capture software to work with GM), can you help?

Hi. Did you find a solution? Thanks!
 
@instaboy Chances are the view was using the "object following" feature while also using an increased application surface size, which many people use without even realizing it. This causes jittering. Best thing to do is move to a manual camera control, and maybe add some smoothing as well.
 

instaboy

Member
@instaboy Chances are the view was using the "object following" feature while also using an increased application surface size, which many people use without even realizing it. This causes jittering. Best thing to do is move to a manual camera control, and maybe add some smoothing as well.
Thanks for the quick answer! I already use manual camera control (tried different versions). The main problem is that the player moves very smooth but other objects/characters are very blurry/jitter/ghosting?. Especially when the player (and the camera) move in the opposite direction than the other objects. It occurs more on higher move speeds, like 2px per step (640*360 base res.). This is really a show stopper. What do you mean by "add some smoothing as well."? Thanks in advance!
 
Thanks for the quick answer! I already use manual camera control (tried different versions). The main problem is that the player moves very smooth but other objects/characters are very blurry/jitter/ghosting?. Especially when the player (and the camera) move in the opposite direction than the other objects. It occurs more on higher move speeds, like 2px per step (640*360 base res.). This is really a show stopper. What do you mean by "add some smoothing as well."? Thanks in advance!
Ah, okay. So, try this. Can you capture the issue in a screenshot? If not, this is likely an art issue. Obviously I've not seen your game, but I'm guessing it is fairly early and using a lot of placeholder art, with bright colors. When things with bright colors move quickly on an LCD monitor, you are more likely to get "ghosting" and other strange looking things. This is not an issue with your code, but with your art. It happens in almost all 2D games with fast motion, but you don't notice it because there are more interesting things to be paying attention to. So ultimately, your only solution is to ignore it until it goes away as your game gets more content and better art.

If you don't believe that is the issue, you could send me a build of your game and I could see if I can reproduce the issue on my machine and offer some further insight.
 

Rekenq

Member
@Pixelated_Pope I saw your tutorials, they're amazing, thanks for sharing all that! I was wondering if there's anyway to keep the quality of sprites when down scaling instead, or should I never down scale at all?
 

Rekenq

Member
Yes. I'm using this code on a project

Code:
if(os_type == os_android)
{
   window_set_size(464,261);
   window_center();
   surface_resize(application_surface,464,261);
}
It is an HTML project that needs to run on both PC and Mobiles. The viewport size is 928x522 (the same as the camera's), which is the max 16:9 resolution we could fit on the page. But this resolution is too big for some mobile devices so we resize the window and surface to half that. The problem is that the animated sprites lose a lot of quality, they show a lot of visual artifacts and aliasing. Should I be doing the opposite? Designing on 464x261 and then up scaling like in your video?
 
Oh, yeah. If you are scaling down pixel art, that's going to look awful. If it's not pixel art, you could just turn on interpolation, and it would look pretty great.
 

Vallo92

Member
Hello @Pixelated_Pope ,
I've seen all your videos on this subject, but unfortunately I'm new enough in GM and I'm having trouble getting your codes working properly in my project, so I'd like to ask you if you can help me.
My project is entirely in pixel art, so I have to make sure that the pixels are correctly scaled, to avoid sprites malformation. The game must be played on a mobile in a vertical position (portrait).
I use a 360x640 room. Here is a sample image of my current room:
example1.png
As you can see inside the room there is a box. I would like that box to always be in that position in whatever resolution is displayed. In short, I need the objects in the room to always be displayed at the usual locations.
So I thought to always keep the usual vertical height, and act on the horizontal background, to match the aspect ratio of the screen of the mobile device (I would like to avoid having black bars in the game).
Following your videos I realized that I could use a wider background, so as to display it if the resolution is greater than 360x640. Here is an example image epr better understand what I mean:
example2.png

Is this method correct?
To make this method work I have to use the views inside GM (I'm not currently using it, and I have placed all my objects based on the room's coordinates).

At the code level, how should I proceed to have a correct size port without black bars, and still have a correct pixel art display?

Thank you so much in advance!
 
Last edited:
Looks like you are on the right path! You need to use views to properly manage your resolution in most cases. Another option is to disable the automatic drawing of the application surface and draw your app surface manually in the GUI event. Then you can maximize the GUI and draw any image you want in the background while drawing your app surface scaled up as much as possible and perfectly centered.
 

Vallo92

Member
Looks like you are on the right path! You need to use views to properly manage your resolution in most cases. Another option is to disable the automatic drawing of the application surface and draw your app surface manually in the GUI event. Then you can maximize the GUI and draw any image you want in the background while drawing your app surface scaled up as much as possible and perfectly centered.
I did a test on my pc with this code (not tested on mobile devices). In your opinion could you go using the view option? As for perfect pixel art scaling, should I have problems?
If I start a test with this code, a window of 720 (h) x1280 (w) is created.
Code:
ideal_width=360;
ideal_height=640;
 
//Aspect ratio
aspect_ratio = display_get_width()/display_get_height();
 
//Calculate new ideal width.
ideal_width=round(ideal_height*aspect_ratio);
ideal_height=round(ideal_width/aspect_ratio);
 
ideal_width=round(ideal_width);
ideal_height=round(ideal_height);
 
if (display_get_width() mod ideal_width != 0) {
    var d = round(display_get_width()/ideal_width);
    ideal_width = display_get_width()/d;
}
if (display_get_height() mod ideal_height != 0) {
    var d = round(display_get_height()/ideal_height);
    ideal_height = display_get_height()/d;
}

if(ideal_width & 1)
  ideal_width++;
 
if(ideal_height & 1)
  ideal_height++;
 
 
 
//Setup all the view ports so I don't have to.
globalvar Main_Camera;
Main_Camera = camera_create_view(0,0,ideal_width,ideal_height,0,noone,0,0,0,0);
camera_set_view_size(Main_Camera,ideal_width,ideal_height);
 
for(var i=1; i<= room_last; i++)
{
  if(room_exists(i))
  {
        room_set_view_enabled(i,true);
        room_set_viewport(i,0,true,0,0,ideal_width,ideal_height);
        room_set_camera(i,0,Main_Camera);
  }
}
 
surface_resize(application_surface,ideal_width,ideal_height);
display_set_gui_size(ideal_width,ideal_height);
window_set_size(ideal_width,ideal_height);
room_goto_next();
Also I wanted to ask you if I can leave my room size at 360x640 and simply insert a larger background, or if I have to enlarge the room completely, so that if the view has to be enlarged the room has free space for it.
 
Last edited:
@Vallo92
Are you on GMS2? If so, you might want to check out my latest tutorial to simplify this a bit. You don't need to create "cameras" or use that for loop to set up the views.
As for your code, I don't see anything immediately wrong with it. you can definitely roll with just using the dynamically sized view.

And, as far as I know, the only thing 'room size' really matters for is when you are using tiles. Other than that, your room can be literally any size.
 
B

BitmapSkies

Guest
quick question what if i want to keep black bars on left and right of screen ? i'm trying to get my view of 320x240 to scale to my 1080p monitor without pixel distortion (i'm using gms2)
 
Last edited by a moderator:
B

BitmapSkies

Guest
@BitmapSkies
GMS1 or GMS2? Also, I recommend joining my discord server (link in my sig) and we can talk about this in real time. Much easier to debug that way.
gms2 i dont use discord wants you to faff about signing up,
its just an extremely basic 2d platformer the pixel art view everything in 320x240 and distorts at full screen on my 1080p monitor i want to keep the none widescreen with the borders on the sides
 
Okay, so since you are on a more square aspect ratio, it's going to stretch your height out to fill the vertical space. So 1080 / 240 = 4.5. That .5 is the cause of any distortion you see. So your only real option is to manually draw the app surface so that it doesn't stretch to fill the whole window. This will result in a "black box" rather than black bars all around your game. But all pixel distortion will be eliminated as you'll be perfectly scaling to 4x instead of 4.5x
 
B

BitmapSkies

Guest
Okay, so since you are on a more square aspect ratio, it's going to stretch your height out to fill the vertical space. So 1080 / 240 = 4.5. That .5 is the cause of any distortion you see. So your only real option is to manually draw the app surface so that it doesn't stretch to fill the whole window. This will result in a "black box" rather than black bars all around your game. But all pixel distortion will be eliminated as you'll be perfectly scaling to 4x instead of 4.5x
ah yes i see cause im asking for the extra height ? hmm now i understand why scaling in none intergers is bad , ok then so gms2 wont work with none widescreen ? how do i stretch the height , keeping black borders on the side without being in a box ? i dont get this considering gms2 is supposed to be mostly for pixel art ? the old gm didnt have this problem dont tell me im going to have to redo all my pixel art for the sake of a few pixels ? its so annoying .
ps : so what should i be using for the pixel art as close to 320x240 to get it to scale without making the game widescreen ? what if it get played on a none exact 1080 screen ? (16 bit platformer)
 
B

BitmapSkies

Guest
ah yes i see cause im asking for the extra height ? hmm now i understand why scaling in none intergers is bad , ok then so gms2 wont work with none widescreen ? how do i stretch the height , keeping black borders on the side without being in a box ? i dont get this considering gms2 is supposed to be mostly for pixel art ? the old gm didnt have this problem dont tell me im going to have to redo all my pixel art for the sake of a few pixels ? its so annoying .
ps : so what should i be using for the pixel art as close to 320x240 to get it to scale without making the game widescreen ? what if it get played on a none exact 1080 screen ? (16 bit platformer)
ps : all this has just reminded me why i stopped making games after gm8
 
@BitmapSkies
This has nothing to do with GameMaker. This is just how graphics work. You have a monitor with a set number of pixels, you have an image with a set number of pixels. If you try to scale the image to fit the monitor, and you have to scale with non-whole numbers, then some pixels are going to be smaller than other pixels. Your monitor is made up of physical pixels, and there's nothing you can do about that. Unless you want to use some fancy shaders to try and smooth out your scaling, you will have pixel distortion. That said, in my experience, depending on the art style, scaling up to anything over 3x usually doesn't look that bad. For example, take this screenshot from Seiken Densetsu 3

it's native resolution is 256x224. But that up there is scaled up to fit a 1080p monitor (if you view the image in full screen.) That's a scale of 4.821428...x Can you spot the pixel distortion? Even if you could pick it out in a static screenshot, I'd bet you'd have a hard time noticing it when actually playing the game. But it is definitely there.



Most people play emulated SNES games at 1080p on their PCs, and very few complain about this sort of distortion; not because it isn't present, but because it isn't noticeable at this scale.

So if you are seeing really serious distortion at your chosen resolution when scaled to 1080, I would first make sure you are scaling correctly and there isn't anything else at play. And then I'd examine your art style... maybe it's making distortion more obvious? I'd have to see a screenshot of your issues to know for sure.
 
B

BitmapSkies

Guest
@BitmapSkies
This has nothing to do with GameMaker. This is just how graphics work. You have a monitor with a set number of pixels, you have an image with a set number of pixels. If you try to scale the image to fit the monitor, and you have to scale with non-whole numbers, then some pixels are going to be smaller than other pixels. Your monitor is made up of physical pixels, and there's nothing you can do about that. Unless you want to use some fancy shaders to try and smooth out your scaling, you will have pixel distortion. That said, in my experience, depending on the art style, scaling up to anything over 3x usually doesn't look that bad. For example, take this screenshot from Seiken Densetsu 3

it's native resolution is 256x224. But that up there is scaled up to fit a 1080p monitor (if you view the image in full screen.) That's a scale of 4.821428...x Can you spot the pixel distortion? Even if you could pick it out in a static screenshot, I'd bet you'd have a hard time noticing it when actually playing the game. But it is definitely there.



Most people play emulated SNES games at 1080p on their PCs, and very few complain about this sort of distortion; not because it isn't present, but because it isn't noticeable at this scale.

So if you are seeing really serious distortion at your chosen resolution when scaled to 1080, I would first make sure you are scaling correctly and there isn't anything else at play. And then I'd examine your art style... maybe it's making distortion more obvious? I'd have to see a screenshot of your issues to know for sure.
yeah i went away calmed down and had a nice brain squeltch, you've basicaly just replied what i was thinking of haha, yeah i'll be honest i'm a big emulator guy so i should know about all this , mabye i got confused by digesting 1000s of hours of pixel art lectures and the beauty of 240pixels of platformer specialisation (since making platformers in widescreen is .... silly unless you design your levels with widescreen in mind , i am however still dumbfounded as to why gamemaker doesnt just add the extra pixels into the borders on the side(how i would like) so doing a little calulator ive worked out the levels need to be made with 480 x 270 in mind ? i am also thinking , that mabye i never noticed the distortion back in 2008 cause i was on a 4:3 crt monitor , i just ran my stone age 2008 gm8 game on my 1080 and yes pixel distortion soooooo ...... looks like im going to be forced to make my levels in widescreen meh .
 
That's not necessarily true either. Your desired aspect ratio is 4:3 (1.3333). So if you pick a desired height that is a whole number factor of 1080 (so either 270 or 216) and then calculate the width based on the desired aspect ratio (1.333) you get two possible, non full screen resolutions that will scale perfectly to 1080p with black bars on the sides: 280 x 216 or 360 x 270. Design your game around either of those resolutions, and you'll scale well on 1920x1080 monitors.
 
B

BitmapSkies

Guest
That's not necessarily true either. Your desired aspect ratio is 4:3 (1.3333). So if you pick a desired height that is a whole number factor of 1080 (so either 270 or 216) and then calculate the width based on the desired aspect ratio (1.333) you get two possible, non full screen resolutions that will scale perfectly to 1080p with black bars on the sides: 280 x 216 or 360 x 270. Design your game around either of those resolutions, and you'll scale well on 1920x1080 monitors.
Thank you so much pope , 280 x 216 was the golden number for my 8 bit games and 360 x 270 for my 16 bit games , you just fixed everything yippeeee !!!! :D
ps: ill have to redo a little pixel art for menus and such but my sprite work is unharmed and now in perfect square pixel but blown up on 1080, also my brother has a 4k screen i wonder what it will look like on his screen hehe thank you again :)
 

Vallo92

Member
Hello,
I'm sorry if I disturb you but I'm having trouble getting your codes to work properly. Here is my current code (I use the last version of GM2):
CREATE:
Code:
///Properties
ideal_width=0; //Doesn't matter because we are going to calculate this.
ideal_height=640;
display_width=display_get_width();
display_height=display_get_height();

//Aspect ratio
aspect_ratio = display_width/display_height;

//Calculate new ideal width or height
ideal_width=round(ideal_height*aspect_ratio);
//ideal_height=round(ideal_width/aspect_ratio);

ideal_width=round(ideal_width);
ideal_height=round(ideal_height);

//Perfect Pixel Scaling
if(display_width mod ideal_width != 0)
{
  var d = round(display_width/ideal_width);
  ideal_width=display_width/d;
}
if(display_height mod ideal_height != 0)
{
  var d = round(display_height/ideal_height);
  ideal_height=display_height/d;
}

//Check to make sure our ideal width and height isn't an odd number, as that's usually not good.
if (ideal_width & 1) {
    ideal_width++;    
}
/*if(ideal_height & 1)
  ideal_height++;*/

surface_resize(application_surface,ideal_width,ideal_height);
display_set_gui_size(ideal_width,ideal_height);
window_set_size(ideal_width,ideal_height);

alarm[0] = 1; // Centra window puoi rimuovere
camera = camera_create();

room_goto(rInizializzazione);
END STEP:
Code:
camera_set_view_size(view_camera[0], ideal_width, ideal_height);
camera_set_view_pos(view_camera[0], room_width/2-camera_get_view_width(view_camera[0])/2, room_height/2-camera_get_view_height(view_camera[0])/2);
ROOM START:
Code:
view_camera[0]=camera;
view_enabled=true;
view_visible[0]=true;
ROOM END:
Code:
view_camera[0]=noone;
This is a result:
exaple.jpg

My game room has dimensions 360x640 (horizontal orientation), and the background I use is 360x640. In the code I inserted an "ideal_height" of 640, just because I would like to keep the original height, and only modify the width to fix the aspect ratio.
The problem is that the height of the window is also changed and the resolution no longer has a height of 640 as you can see from the screen). Is it not possible to make the camera have a height that perfectly covers the height of the background?

Running the code on a mobile device, I encounter problems in the click of many objects that have been placed inside the room through normal coordinates (they are displayed correctly). Do I have to place them by code based on other coordinates?
 
Last edited:
Hello,
I'm sorry if I disturb you but I'm having trouble getting your codes to work properly. Here is my current code (I use the last version of GM2):
CREATE:
Code:
///Properties
ideal_width=0; //Doesn't matter because we are going to calculate this.
ideal_height=640;
display_width=display_get_width();
display_height=display_get_height();

//Aspect ratio
aspect_ratio = display_width/display_height;

//Calculate new ideal width or height
ideal_width=round(ideal_height*aspect_ratio);
//ideal_height=round(ideal_width/aspect_ratio);

ideal_width=round(ideal_width);
ideal_height=round(ideal_height);

//Perfect Pixel Scaling
if(display_width mod ideal_width != 0)
{
  var d = round(display_width/ideal_width);
  ideal_width=display_width/d;
}
if(display_height mod ideal_height != 0)
{
  var d = round(display_height/ideal_height);
  ideal_height=display_height/d;
}

//Check to make sure our ideal width and height isn't an odd number, as that's usually not good.
if (ideal_width & 1) {
    ideal_width++;   
}
/*if(ideal_height & 1)
  ideal_height++;*/

surface_resize(application_surface,ideal_width,ideal_height);
display_set_gui_size(ideal_width,ideal_height);
window_set_size(ideal_width,ideal_height);

alarm[0] = 1; // Centra window puoi rimuovere
camera = camera_create();

room_goto(rInizializzazione);
END STEP:
Code:
camera_set_view_size(view_camera[0], ideal_width, ideal_height);
camera_set_view_pos(view_camera[0], room_width/2-camera_get_view_width(view_camera[0])/2, room_height/2-camera_get_view_height(view_camera[0])/2);
ROOM START:
Code:
view_camera[0]=camera;
view_enabled=true;
view_visible[0]=true;
ROOM END:
Code:
view_camera[0]=noone;
This is a result:

My game room has dimensions 360x640 (horizontal orientation), and the background I use is 360x640. In the code I inserted an "ideal_height" of 640, just because I would like to keep the original height, and only modify the width to fix the aspect ratio.
The problem is that the height of the window is also changed and the resolution no longer has a height of 640 as you can see from the screen). Is it not possible to make the camera have a height that perfectly covers the height of the background?

Running the code on a mobile device, I encounter problems in the click of many objects that have been placed inside the room through normal coordinates (they are displayed correctly). Do I have to place them by code based on other coordinates?
Okay, first off, since you are developing your game for a mobile device in portrait mode but aren't developing your game on a monitor in portrait mode, you will need to replace "display_get_width & height" with hard coded values to get your game window to display properly when building locally.

As for your other issues with GUI elements, that's a completely different issue, but one I've also released a video on:

It's a complicated problem, but this is how I solve it for my projects that support different aspect ratios.

It also seems you are using the older version of my system. You may be interested in my Super Simple system:
 

Vallo92

Member
Hi @Pixelated_Pope ,
I have already used your scaling system on my project, and it works perfectly.
I recently started a new project with pixelart graphics, and I had a problem that I can't solve.
The game room I use has dimensions 288 (w) x512 (h) (9:16).
This is the current code that I use in the first room as soon as the game is started:
Create Event:
Code:
///Properties
ideal_width=0; //Doesn't matter because we are going to calculate this.
ideal_height=512;
display_width=display_get_width();
display_height=display_get_height();

//Aspect ratio
aspect_ratio = display_width/display_height;

//Calculate new ideal width or height
ideal_width=round(ideal_height*aspect_ratio);
//ideal_height=round(ideal_width/aspect_ratio);

ideal_width=round(ideal_width);
//ideal_height=round(ideal_height);

//Perfect Pixel Scaling
if(display_width mod ideal_width != 0)
{
  var d = round(display_width/ideal_width);
  ideal_width=display_width/d;
}
if(display_height mod ideal_height != 0)
{
  var d = round(display_height/ideal_height);
  ideal_height=display_height/d;
}

//Check to make sure our ideal width and height isn't an odd number, as that's usually not good.
if (ideal_width & 1) {
    ideal_width++;  
}
if(ideal_height & 1) {
  ideal_height++;
}

surface_resize(application_surface,ideal_width,ideal_height);
display_set_gui_size(ideal_width,ideal_height);
if (os_type == os_windows || os_type == os_macosx || os_type == os_linux) {
    window_set_size(ideal_width,ideal_height);
}
room_goto(rGame);
End Step Event:
Code:
camera_set_view_size(view_camera[0], ideal_width, ideal_height);
camera_set_view_pos(view_camera[0], room_width/2-camera_get_view_width(view_camera[0])/2, room_height/2-camera_get_view_height(view_camera[0])/2);
Room Start Event:
Code:
view_enabled=true;
view_visible[0]=true;
show_debug_message(ideal_width);
show_debug_message(ideal_height);

The result of the two show_debug_message is this (see the Room Start Event code):
854.33
480

I can't understand why my ideal_height is lowered to 480, while I set it to 512. If the ideal_height is increased to maintain the aspect ratio, it's fine (I think it's a normal thing), but if it gets smaller, I have serious space problems.
Can you tell me why this happens to me? Is there no way to prevent the ideal_height from decreasing, but only to maintain its value or increase?
 
Yeah, you can definitely alter the math to favor going up rather than going down. In the pixel perfect block of code, instead of rounding the calculations, just use ceil().
 
Hi Pixelated_Pope,

I'm having issues with pixel-perfect scaling for Iphone and I was wondering if you could help me. I can't find the exact answer inside your tutorial so that's why I'm asking here.

My game is developed for iOS, Android and Windows. The view size is 320x180 (16:9) which means it scales well on most Android devices and PC screens, because it almost always scales at integer values (x2,x3,x4,...)
However, Iphones 6 to 8 use a resolution of 1334x750, which is 16:9, but scales up with a non-integer value: 4,167.
The result is pixel deformation and it is incredibly noticable.

I can of course change the view size on these devices to make a bettter fit, but this means more (or less) of my room is visible and I would like to keep this the same between platforms.

I tried to limit the application surface to integer scaling only (in the case of 1334x750: x4), meaning the application surface will be smaller than the screen, centered with black bars around it.
However, this does not work, because the application surface position doesn't match the drawn application surface (Gamemaker can only keep aspect ratio or stretch). Example: Some of my objects are clickable and the game thinks they're in a different position than they're drawn, so the clicking is off.

My question is: Is there a better or alternative way to achieve pixel-perfect scaling on these Iphone devices?

Thanks in advance
 
Hi Pixelated_Pope,

I'm having issues with pixel-perfect scaling for Iphone and I was wondering if you could help me. I can't find the exact answer inside your tutorial so that's why I'm asking here.

My game is developed for iOS, Android and Windows. The view size is 320x180 (16:9) which means it scales well on most Android devices and PC screens, because it almost always scales at integer values (x2,x3,x4,...)
However, Iphones 6 to 8 use a resolution of 1334x750, which is 16:9, but scales up with a non-integer value: 4,167.
The result is pixel deformation and it is incredibly noticable.

I can of course change the view size on these devices to make a bettter fit, but this means more (or less) of my room is visible and I would like to keep this the same between platforms.

I tried to limit the application surface to integer scaling only (in the case of 1334x750: x4), meaning the application surface will be smaller than the screen, centered with black bars around it.
However, this does not work, because the application surface position doesn't match the drawn application surface (Gamemaker can only keep aspect ratio or stretch). Example: Some of my objects are clickable and the game thinks they're in a different position than they're drawn, so the clicking is off.

My question is: Is there a better or alternative way to achieve pixel-perfect scaling on these Iphone devices?

Thanks in advance
For that last solution to work, you would need to draw the application manually yourself. You can disable the automatic drawing of the app surface and then draw it yourself in a post-draw or draw GUI event.
 
For that last solution to work, you would need to draw the application manually yourself. You can disable the automatic drawing of the app surface and then draw it yourself in a post-draw or draw GUI event.
That doesn't work, the actual application surface position is not the same as the drawn application surface position in this case.
Maybe I'm doing something wrong, but I'll try to demonstrate it in a sample project (it's about scaling for 800x600, because it makes the effect more clear, but the idea is the same).

I made an example in this project (it's .gmz, I hope that's OK, it can easily imported in GMS2)

Press "A" to change graphics mode between aspect ratio, pixel-perfect and stretched.

Click the squares to make them black.

Notice when the mode is set to pixel-perfect, the clicking is slightly off. Also, actual and drawn application surface sizes don't match.
 
Last edited:
@Pineapple I don't really understand why you are drawing the app surface that way instead of just drawing it with a calculated scale, here's how I would do it:

console create:
Code:
ideal_width = 320;
ideal_height = 180;

application_surface_draw_enable(false);
window_set_size(1200,300); //or whatever
display_set_gui_size(ideal_width,ideal_height);
console step
Code:
scale = floor(min(window_get_width()/ideal_width,window_get_height()/ideal_height))
console post-draw
Code:
var _xoff = window_get_width()/2 - (ideal_width*scale/2);
var _yoff = window_get_height()/2 - (ideal_height*scale/2);

draw_surface_ext(application_surface,_xoff,_yoff,scale,scale,0,c_white,1);

as for the mouse position detection thing, that's a bit of a pain. But it is possible to convert the window mouse coordinates to be relative to the room. Keep in mind, however, that this code does not take into account a moving camera. And if you start using the GUI layer for your UI, well things will just get even more complicated.

console begin step
Code:
var _win_w = window_get_width();
var _win_h = window_get_height();
var _ideal_w = console.ideal_width;
var _ideal_h = console.ideal_height;
var _game_w = _ideal_w*scale;
var _game_h = _ideal_h*scale;

var _xmarg = (_game_w-_win_w)/(scale*2);
var _ymarg = (_game_h-_win_h)/(scale*2);

global.mx = lerp(_xmarg,_ideal_w-_xmarg,window_mouse_get_x()/_win_w);
global.my = lerp(_ymarg,_ideal_h-_ymarg,window_mouse_get_y()/_win_h);
global.mx and global.my are your new "mouse_x" and "mouse_y" Which means you can no longer use the built in mouse events. So I added this step event to obj_square
Code:
if(point_in_rectangle(global.mx,global.my,bbox_left,bbox_top,bbox_right,bbox_bottom))
    image_blend=c_black;
else
    image_blend=c_white;
And the result:
https://gyazo.com/9bce9fa5ce2cdf4f4696f5b9581fe148
 
Top