Seamless Screen-Scaling
Game MakerThis is a tutorial how to get around using GM's built-in screen-scaling, which has an often undesired blur-effect when scaling up. An alternate method was to scale the view-port dimensions to scale the view. The problem with the view-port method is that it causes ugly seams to appear in your graphics when displayed on certain machines.
Thus, we're going to use the surface-method. The good thing about this method is you can apply it to your game easily, because none of your drawing events or anything need to be changed. You just have to make one persistent object at the beginning of the game, be consistent with your scaling, and you're set.
With this method, we will be changing the view-ports as well. This is a sure-fire method, because if the graphics card doesn't support surfaces, it'll automatically revert to using the view-port method, which is better than nothing, right?
So here we go.
STEP 1: Choose the scale you want. Use a view for every room and have the port W and port H scaled appropriately. So, for example, if you were using a scale of 2... it would look like this, in GM's room editor.
It is important that this is consistent for all rooms. If you have lots of rooms, it might be easier to do this via code
*. I prefer to do it that way, because then the values aren't constant and I can support multiple different scales.
STEP 2: Create 3 scripts,
screen_init,
screen_begin, and
screen_end. Here is what goes in each of the scripts...
// screen base(view_wview and view_hview)
screen_x = 0;
screen_y = 0;
screen_w = 320;
screen_h = 240;
screen_scale = 2;
// create a surface for the whole screen to be drawn on
screen = surface_create(screen_w,screen_h);
// this will destroy the screen object if surfaces are not supported on the graphics card, reverting to the viewport method
if screen = -1{instance_destroy();}
// this draws the surface on the screen
surface_reset_target();
draw_clear(0);
draw_set_blend_mode_ext(bm_one, bm_zero);
draw_surface_stretched(screen,screen_x,screen_y,screen_w*screen_scale,screen_h*screen_scale);
draw_set_blend_mode(bm_normal);
screen_refresh();
// this sets surface 'screen' as the drawing target for everything in the game, so all drawing will be done on this surface and not on the game screen
surface_set_target(screen);
STEP 3: Now we have are scripts, but where do they go? Create an object. Like, obj_screen, objScreen, o_screen, or whatever, and do the following:
A) place the
screen_initscript in the
Create event.
B) place the
screen_begin script in the
Begin Step event.
C) place the
screen_end script in the
End Step event.
And place that object in the
first and foremost room of your game, mark it
persistent, and make sure there are no duplicates of it.
You're done, and now have nice, crisp scaling TIPS:*Here's how I defined all my rooms in Skullpogo. Instead of going through every room in the game and setting its view dimensions, I just defined it all here in one neat little piece of code at the beginning of the game (right after the screen_init script, actually, because you need to use variables defined in it).
var w,h;
w=240*screen_scale;
h=320*screen_scale;
room_set_view(rmSplash,0,true,0,0,240,320,0,0,w,h,0,0,0,0,noone);
room_set_view(rmIntro,0,true,0,320,240,320,0,0,w,h,0,0,0,0,noone);
room_set_view(rmGame,0,true,0,0,240,320,0,0,w,h,0,0,0,0,noone);
room_set_view(rmHelp,0,true,0,0,240,320,0,0,w,h,0,0,0,0,noone);
room_set_view(rmScore,0,true,0,0,240,320,0,0,w,h,0,0,0,0,noone);
room_set_view(rmEnd,0,true,0,0,240,320,0,0,w,h,0,0,0,0,noone);
Things to note about doing it this way:
1) Advantage: because if you decide to change your game's scale, you can do it by just changing the screen_scale value. One little number change and its all done.
2) Foresight: what if you want to have the user choose between multiple game scales? Well, you could have the player choose the scale value at the beginning of the game, and then call this script to set all the rooms. Actually that's exactly what I did in Skullpogo.
3)
WARNING: You'll notice that I used room_set_view because it can change the view settings in
other rooms. Don't change the view port for the room you're in, the results won't be pleasant. I did this all from an INIT room at the beginning of the game, the room itself which doesn't have any view specifications. So make sure this isn't called from any of the rooms that are being altered.
4) Possibilities! Now your whole screen is drawn on a single surface, which can be moved, rotated, stretched, cut up, or manipulated as you please. The latest I made was an effect where the screen spins away into the background, and I took out the draw_blank(0) for the effect, so the screen leaves behind images as it whirls away in the transition. You can also change the color of the screen, save it to external files, darken/lighten it, or even apply screen filters (which I've also covered with my Retro Remakes project).
~*~
So if you got that working, here's a side project for you. Notice that in screen_init, I defined variables for screen_x and screen_y. But so far, they've just sat at zero and don't do anything. With this, you could create a little function that "jumps" that x and y value around a bit, giving the screen a "shaking" effect, and at the end of the effect snapping them back to zero. Or, you could have the screen
slide off one side of the screen as a sort of transition.
~*~
Anyhow, enjoy folks. I'm currently working on an advanced GML library/extension called DeftScreen which will be used to handle a bunch of screen, scaling, and view effects and functions with ease. So that'll go here when it's done, too.
Questions can be PMed to me, posted here, or emailed to me (
[email protected]). I'm always glad to help.
ChevyRay