How to properly scale your game!

A

Alessio

Guest
And what happens after? You get a black screen?
Because you have to draw the surface every step. If you have it only in your ini object that won't do.
What do you mean? And, ops, yeah, i forgot to mention that i get only a black screen.
What's the problem with the init object? It's persistent. Isn't it drawn every step?
 

RangerX

Member
Yeah if that object is persistent of course its post draw event is read every step.
However, why do you set the application surface stuff every step? That is useless an odd.
Do it ONCE in your object's create event. We'll start with that.
 
A

Alessio

Guest
Oh, great, i'm a beginner so i didn't have idea why all the code didn't have to run every step but only once.
That works now, yeah!

I've only one issue, but that may be the actual effect.
Should this solution scale up the pixels too? Or only the surfaces? Because my objects move smoothly, between pixels, like with the default view settings,
Shouldn't it scale up everything in a total pixel-perfect way?
 

RangerX

Member
With this you're supposed to make your game displayed as big as possible without damaging the graphic, your game therefore being "pixel perfect".
This if you done it correctly. ;)
 
A

Alessio

Guest
With this you're supposed to make your game displayed as big as possible without damaging the graphic, your game therefore being "pixel perfect".
This if you done it correctly. ;)
No, graphics aren't damaged, that's sure. Mine was another question.
Wanna be more clear.
With this setting, when sprites are rotated, they are in an "Undertale" style, namely, you can see that the pixels are rotated, because of the high resolution.
While, sometimes, if you scale everything, even the pixels, you get a "Snes" style, namely, the sprite rotates with artifacts, because of the low resolution.

Therefore, with this method, are sprites supposed to rotate in an "Undertale" style?
 

RangerX

Member
Ok I see. With your game scaled up the graphics are staying the same, original style, looking like the original resolution.
Its the whole screen that is scaled up (application surface) with everything already drawn on it.

If you want high res rotation, your graphics needs to be high res.
 
A

Alessio

Guest
Maybe i didn't explain well.
In my 256x240 resolution, the graphics are stayng the same. But when they rotate, they give a "perfect rotation" to pixel (example), which is weird in pixel art (something you also see in Super Mario Maker).
Aren't they supposed to rotate in a SNES fashion (example), with these settings?
 

RangerX

Member
Actually it depends the workflow you decide to take. I am not going in-depth regarding this with the tutorial here but its a valid concern.
If you do it this way:

1- Not resizing the application surface at startup
2- Game is drawn on the 256x240 resolution
3- Application surface is drawn on screen scaled up

This way your rotations won't be "high res", they will be looking like 256x240 rotation.
However, if you do this:

1- Resize the application surface at startup
2- Game is drawn on the scaled up surface
3- Application surface is simply drawn on screen

Now you get "high res" rotations since your game is drawn on a canvas that contains more pixels.
 

Artwark

Member
Ok so I tried this and I put it on the creation code in the room

var base_w = 1024;
var base_h = 768;
var max_w = display_get_width();
var max_h = display_get_height();
var aspect = display_get_width() / display_get_height();
if (max_w < max_h)
{
// portait
var VIEW_WIDTH = min(base_w, max_w);
var VIEW_HEIGHT = VIEW_WIDTH / aspect;
}
else
{
// landscape
var VIEW_HEIGHT = min(base_h, max_h);
var VIEW_WIDTH = VIEW_HEIGHT * aspect;
}

view_wview[0] = floor(VIEW_WIDTH);
view_hview[0] = floor(VIEW_HEIGHT);
view_wport[0] = max_w;
view_hport[0] = max_h;

surface_resize(application_surface, view_wview[0], view_hview[0]);

But this doesn't work on any device besides the one that I keep using for the game as the sprites don't stay in the same position and all. I do have a problem with one object that's a virtual key where the virtual_add function is outside of its sprite and I don't know how to keep it within the sprite unlike in the windows version. I think that I lack some understanding of the logic here. Can anyone help me here?
 
M

milk

Guest
hi, is there a way to use your first method but have the screen start out windowed at the original resolution? then when you push alt+enter to full screen it does the scaling? i dont want it to automatically start at full screen but when I take out that piece of code and it starts windowed it's not centered in the window and still has a black space around it
 
M

milk

Guest
Of course you can. Start your game without triggering the first method code.
how do I do that? I'm sorry I'm new at this, is there something I need to add to the code to only trigger it when pushing alt+enter? what do I need to add?
 

RangerX

Member
You could put the scaling code in a key press event yes. So when that key is pressed, scaling would become on.
I cannot walk you through making a whole option menu though, its quite a long page of code depending how you want to do it.
 
M

milk

Guest
ok I changed the create event into a key press event but now when I run the game I get this error:
global variable Yoffset(100000, -2147483648) not set before reading it.
at gml_Object_obj_init_DrawPost_1 (line 1) - draw_surface_ext(application_surface,global.Xoffset,global.Yoffset,1,1,0,c_white,1);

I think the postdraw event I had with it is messing it up, do I need to change the post draw event to something else?
 

RangerX

Member
This error means that when the game is reading the Post Draw event of your object called "obj_init", the variable global.Yoffset is not yet created --- therefore it crashes.
 
M

milk

Guest
so how do I make it take effect only AFTER I trigger the full screen with the key press event? when I remove the postdraw event the game runs without error, but when I trigger full screen with a key press the screen goes black.
 

RangerX

Member
so how do I make it take effect only AFTER I trigger the full screen with the key press event? when I remove the postdraw event the game runs without error, but when I trigger full screen with a key press the screen goes black.
You don't seem to grasp what you are doing. This makes me hard for me to guess where to start explaining stuff.
Normally if you follow this tutorial, at the very beginning of the game you create those global variables Xoffset and Yoffset. If you don't want to scale up at the opening of the game then don't scale, create those variable as "0" and therefore your post draw code will not crash since Yoffset and Xoffset will exist at the moment the engine reads it.

Then in your key press event, you reajust everything, almost just a copy-paste of this tutorial really. But if you don't grasp what you're doing, you will not be able to adapt the smallest concept to your situation. You have to adapt code and apply concepts to your game's reality, no tutorial will do that for you.
 
M

milk

Guest
I said I was new at this, I'm sorry. I wont ask anymore questions here
 

RangerX

Member
Don't be, we all new to something. I suck at everything I didn't try yet am sure lol.
But I suggest you start from the start. Use the programming forum alot, people are generally helpful even if the question is something that might be very basic.
 
S

SmallyBiggs

Guest
3) Games with their displayed playfield changing size. (good for some very specific cases)

With this method you would actually set the view and port size of your room according the monitor's size. It's very easy to pull off and will be useful mostly in games like SimCity or other strategy games where the gameplay is not broken due to the fact a player can see larger of a playfield than another. It's rare you see this method used in professional games though because there are some drawbacks to understand before using it:
[/QUOTE]

Thank you for such a thorough post! If I wanted to use this method, shouldn't putting something like the following in the room creation code work? :

Code:
global.MonitorW=display_get_width();
global.MonitorH=display_get_height();
view_xview[0]=global.MonitorW
view_yview[0]=global.MonitorH
view_xport[0]=global.MonitorW
view_yport[0]=global.MonitorH
I thought this would work, but I am only very basically familiar with code. Also, is it posible to test this method by simply resizing the game window (by clicking and dragging when the "allow players to resize windows options" is on) ?
 
S

SmallyBiggs

Guest
View width is the variable "view_wview"
View height is the variable "view_hview"

I think its the same logic for ports. I'd have to look up the manual to confirm though.
You might want to use "room_set_view" though, its all in there. See manual again. :)

https://docs.yoyogames.com/source/dadiospice/002_reference/rooms/room_set_view.html
Thank You! I'll experiment with these codes. If I decide to use this method, is it possible to set a maximum view size? So that when its played on a large device, it cannot exceed a given view size?
 
S

SmallyBiggs

Guest
***sorry I botched this post before - edited ***
Yes of course, with a simple conditional logic you will achieve this easily.
I managed to get this far, but the images are stretched instead maintaining their aspect ratio. I do have this option set in the global game settings. :
Code:
global.MonitorW=display_get_width();
global.MonitorH=display_get_height();

if global.MonitorW>=512
{view_wview[0]=1024
view_wport[0]=512}
else
{view_wview[0]=global.MonitorW
view_wport[0]=global.MonitorW}

if global.MonitorH>=288
{view_wview[0]=576
view_wport[0]=288}
else
{view_wview[0]=global.MonitorH
view_wport[0]=global.MonitorH}
 
Last edited by a moderator:

RangerX

Member
First off you set the width of the view and port 2 times. Set the width once and the height once.
Second thing, the view and the port should always be same size.
 
S

SmallyBiggs

Guest
First off you set the width of the view and port 2 times. Set the width once and the height once.
:bash:I accidentally typed "w" instead of "h" and racked my head for hours over it....


As for the view and port sizes, I set it that way because I need the actual view of the room to be larger than the "viewport". So I figured as long as I keep the ratios intact, it shouldn't get warped.
Though there is loss of detail as I'm currently using 64x64 sprites. Should I be aproching this a different way?
 

RangerX

Member
Totally. I don't see how squishing a larger view into a smaller port can be useful (outside ruining graphics). Have the view the same size as the port on screen. Scale up with the application surface.
 

Xer0botXer0

Senpai
Thanks for clearing this up, can I just confirm that if you dont increase the size by two or other even number then some of the pixels will be left unscaled thus making it look funky ?
 

RangerX

Member
Thanks for clearing this up, can I just confirm that if you dont increase the size by two or other even number then some of the pixels will be left unscaled thus making it look funky ?
Yes or unevenly scaled up, just like Yellow Bob in the opening post ;)
 
S

SmallyBiggs

Guest
Totally. I don't see how squishing a larger view into a smaller port can be useful (outside ruining graphics). Have the view the same size as the port on screen. Scale up with the application surface.
Thanks Again! I had a feeling I wasn't approaching this right. But, I'm confused about "scaling up with the application surface". I'm gathering that if I set the view and ports the same size, maybe I should work on a 32x32 scale instead of 64x64? Here's more info:

My game takes place in a 1724x960 room. And I'm working on a 64x64 scale. I basically wanted the screen size to be the scope of view in the room, but the sprites appear too large at this scale, not allowing enough of the room to be viewed. Which is why my solution was to make the view twice as large as the current screen. Which obviously results in loss of detail. But after reading the info you provided before, I'm assuming that I need to work with 32x32 sprites, and make the view and ports the same. And I'd obviously make the room half the size. Am I understanding that right?o_O
 
Last edited by a moderator:

RangerX

Member
You probably don't get it right as I simply don't understand what you're saying like AT ALL. Your sprite or tile size or room size have nothing to do with scaling. Like at all. Let's make sure you understand the basics really:

- Room (the canvas you work in, your "level" or "world" or whatever you decide to name that canvas).
- View (the portion of the room you want to see at once on screen).
- View port (the size of the port on screen that the view will be displayed in).
- Application surface (the surface on which the view is drawn except for the GUI layer which is on top of it. Then that surface is then drawn on screen)


To scale your game you will generally want to draw everything "as is" and then scale up the application surface when its drawn on screen. Your view size is basically your game's resolution as it will become the size of the application surface that, in turn will be scaled up to fit the screen. If you feel your graphics looks too zoomed in, too large, then have a bigger view or smaller graphics. But whenever you decide on a new view size, keep in mind it should probably be a 16:9 aspect ratio size so it can scale up fine. Most screens, PC, tablets, phones, are getting 16:9 is aspect ratio.
 
S

SmallyBiggs

Guest
You probably don't get it right as I simply don't understand what you're saying like AT ALL. Your sprite or tile size or room size have nothing to do with scaling. Like at all. Let's make sure you understand the basics really:

- Room (the canvas you work in, your "level" or "world" or whatever you decide to name that canvas).
- View (the portion of the room you want to see at once on screen).
- View port (the size of the port on screen that the view will be displayed in).
- Application surface (the surface on which the view is drawn except for the GUI layer which is on top of it. Then that surface is then drawn on screen)


To scale your game you will generally want to draw everything "as is" and then scale up the application surface when its drawn on screen. Your view size is basically your game's resolution as it will become the size of the application surface that, in turn will be scaled up to fit the screen. If you feel your graphics looks too zoomed in, too large, then have a bigger view or smaller graphics. But whenever you decide on a new view size, keep in mind it should probably be a 16:9 aspect ratio size so it can scale up fine. Most screens, PC, tablets, phones, are getting 16:9 is aspect ratio.
AH, I believe I was confusing view port and application surface, (among other things). Thanks for clarifying!
 

Brenden

Member
So, after like months of trying to get the pixel perfect method to work I figured it out!
every code was fine the only problem was I had the draw surface code in a draw event but i needed it in a draw gui event.
The only other problem is the x and y offset offsets the surface too far to the right.
Code:
    global.Xoffset=(global.MonitorW-global.gameW*global.scale)/2;
    global.Yoffset=(global.MonitorH-global.gameH*global.scale)/2;
 

RangerX

Member
The GUI event is something I did not factor at all in the tutorial. It might be the cause why my offset logic doesn't work.
Anyhow, the offset is easy to understand. If per example your screen resolution is 1920x1080 and your application surface 1600x900, you need to center that smaller surface in the middle of the screen. So basically, you want to find what is the size of that space that will end up all around the application surface right? So 1920 - 1600 = 320. That's the difference in size on the X axis. If you place application surface on screen at X+320 the app surf will be in line with the right side of the screen when you want it in the middle. Thats why you divide that value by 2. With 160 pixels on each side, the application surface in the example here is right in the middle of the X axis.

global.Xoffset=(global.MonitorW-1600)/2;
global.Xoffset=(1920-1600)/2; // 160!
 
Last edited:

Brenden

Member
Ya, I understand the concept and I went over my code but nothing seems to be the problem besides the offset and as you can see in my code above nothing should be wrong.
 

zendraw

Member
why does my pixels gets deformed with this resolutions

576x576 on both view tabs in the room editor
but when i set them to 512x512 it stops being deformed?

i also floor the view x/y positions.

also the view is static, it doesnt move.
 

RangerX

Member
why does my pixels gets deformed with this resolutions

576x576 on both view tabs in the room editor
but when i set them to 512x512 it stops being deformed?

i also floor the view x/y positions.

also the view is static, it doesnt move.
It depends at which resolution you display the game. Depends if you are set into "keep aspect ratio". Can be something wrong in your code if you used the "pixel perfect method".
Could be many things really. I would need more detail. If you view doesn't move, its not even related to scaling.
 

zendraw

Member
i dont really do anything specific, just set the view options in the views tab to 576, also keep aspect ratio is set and i didnt use any code, now i used this code.
Code:
if(surface_exists(application_surface))
{
    if(surface_get_width(application_surface)!=576)
    {
    surface_resize(application_surface, 576, 576);
    }
}
and it fixed it slightly, but theres still deformation.
 

RangerX

Member
Ok so your game is 576x576. Now what is the resolution of the monitor you displayed it in and where it appear deformed still?
 

zendraw

Member
my monitor is 1280x1024, and its like deformed in couple of places horizontally and vertically thepixels are thinner, and its deformed in both full and windowed screen.
 

RangerX

Member
Its normal that you get deformation. "Keep aspect ratio" makes sure your game doesn't stretch, but it will scale it up as much as possible. It doesn't care your game gets scaled up by an integer or a fraction. Taking your game as an example:

Your game is a 576x576 square. Therefore it gets resized as a 1024x1024 square in your TV and get some black bars on the left and right of the screen, 1024 being the biggest square that can fit in this 1280x1024 rectangle right?
1024 divided by 576 = 1,77
Your game is scaled up 1,77 times on screen. Fractions of pixels don't exists. The engine needs to compensate (and therefore screw your graphic). Precisely what I demonstrate at the beginning of the tutorial with Yellow Bob.
To not have any deformation, you game always need to scale up an integer value (2, 3, 4, etc). And to make sure this happens, you need to use the "pixel perfect" method.
 

zendraw

Member
i will be trying the pp way you suggest now, but does it neceserly need to be fullscreen? in my game i want the option to make it windowed.
 

RangerX

Member
You can do anything you want, up to you.
In my game per example, I start fullscreen but I have options for scaling, windowed, etc
 

zendraw

Member
so i tryed the pixel perfect method and from what i see the resolution just has to be an integer or w/e like 1-2-4-8-16-32 til 1024, so the resolution of my game has to be 512, with 576 it cant work.

this is the code overall, its not optimised or things like that, its raw. also bare in mind the window is to be box like.

this is the post draw event.
Code:
var wos=0;

if (window_get_fullscreen())
{
    var ht=display_get_height();
    wos=floor((display_get_width()-ht)/2);
    
    if(surface_exists(application_surface))
    {
        if(surface_get_width(application_surface)!=ht)
        {
            surface_resize(application_surface, ht, ht);
        }
    }
} else
{
    
    if(surface_exists(application_surface))
    {
        if(surface_get_width(application_surface)!=576)
        {
            surface_resize(application_surface, 576, 576);
        }
    }
}

draw_surface_ext(application_surface, wos, 0, 1, 1, 0, c_white, 1);
 

RangerX

Member
No, with the pixel perfect method, your game will be displayed 576x576 up until 1152x1152 fits on screen. Then will be drawn 1152x1152 until 1728x1728 fits.
That's the whole point of the pixel perfect method, drawing your game as big as possible on screen but scaling it only by an integer value.

So what you need to do when your game opens is to check the monitor size, if its less than 1152, your game is scale 1. If its more than 1152, scale the app surf x2. If its more than 1728, scale up the app surf x3 and so on.
 

zendraw

Member
so overall the reason game maker doesnt display pixel perfect is cus it tryes to fit the game to the screen? otherwise its displayed pixel perfect if it matches your screen resolution by an integer?
 

RangerX

Member
so overall the reason game maker doesnt display pixel perfect is cus it tryes to fit the game to the screen? otherwise its displayed pixel perfect if it matches your screen resolution by an integer?
Basically GameMaker is offering 2 solutions for you without the need to code anything:

- Keep Aspect Ratio (which means the game will be displayed as big as possible without stretching -> but not minding if it ends up being resized by an integer factor or not.
- Full scale (which means the game is stretched over the whole screen, regardless of everything)




Since GameMaker doesn't do the "pixel perfect" method automatically for you, that's why you have to do it yourself and why this tutorial exist.
 
Top