The Basics Of Scaling - HTML5


The Basics Of Scaling - HTML5

This blog post is a continuation from The Basics Of Scaling - The Game View where we looked at different methods to scale the game view so that it can be adapted to the different screen sizes and aspect ratios of any given device or display.

After the previous two tech blogs about scaling for different display sizes, it's time to tackle how to scale games for the HTML5 target platform, as it poses some unique challenges compared to all the other platforms.

Main screen

When scaling your game on the HTML5 target, it is important to realise that there are some fundamental differences between it and the desktop/device targets. The game window is now the canvas element of the page, and the display becomes the browser window. This tech blog will take you through three steps to show how to scale a single room to a required size, how to scale a room that uses viewports and cameras to a required size, and finally how to scale a room with viewports and cameras to fill the entire browser window.

NOTE: For this tutorial, you should have the HTML5 Game Options set to not be centered (since we will do that in our code), and the scaling option should be set to Full Scale since we will be dealing with aspect ratio as well.


SCALING A SINGLE ROOM

Scaling the game canvas to the browser is actually very simple and can be done with a single short script. The only complication is that the browser can be resized to be taller than it is wider at any time (unlike the average desktop or device display) and this possibility has to be taken into account when scaling the game. So, to start with, you will need some controller object that is placed in your game rooms - it could be a persistent object rather than have one in every room - as we'll use it to detect any changes to the browser width or height. This controller should have a Create Event with the following:

base_width = room_width;
base_height = room_height;
width = base_width;
height = base_height;

The base width and height variables are the base values that we want our canvas element to be set to (as we did in the previous tech blogs), and in this case it's the room width and height as in this example we aren't using cameras and viewports (note that you could make the base width and height values as Macros, which means that they will be highlighted in the script editor and also compile faster). We also need two extra variables that will be used to detect when the browser width or height changes. We initialise these to the size of the game room as the code you will add next will then set them to the correct size for the current browser state.

We are going to make the following code a script as, unlike previous scaling options, we will be re-using this one every time the user re-sizes the game canvas, so you should create a script and call it something like scale_canvas() and add the following:

/// @function                       scale_canvas(base width, base height, current width, current height, center);
/// @param {int}    base width      The base width for the game room
/// @param {int}    base height     The base height for the game room
/// @param {int}    current width   The current width of the game canvas
/// @param {int}    current height  The current height of the game canvas
/// @param {bool}   center          Set whether to center the game window on the canvas or not

var _bw = argument0;
var _bh = argument1;
var _cw = argument2;
var _ch = argument3;
var _center = argument4;
var _aspect = (_bw / _bh);

if ((_cw / _aspect) > _ch)
    {
    window_set_size((_ch *_aspect), _ch);
    }
else
    {
    window_set_size(_cw, (_cw / _aspect));
    }
if (_center)
    {
    window_center();
    }

surface_resize(application_surface, min(window_get_width(), _bw), min(window_get_height(), _bh));

As you can see from this code, we are getting the base aspect ratio and then using that to scale the window (the game canvas). We also scale the application surface to fit, much like we do for devices. Now, when you run your game, no matter what the user sets their browser size to be, the game will be scaled to a "best fit" along the horizontal or vertical axis.

NOTE: You can see that there is an argument to center the game window. This is optional, and it's only included here to show that it is possible to position the canvas within the browser using this function (the other windows position functions will work too).

Great, we have our script, but now what to do with it? We need to call it in the Step Event of our controller object so that it is checked and run every time the browser window changes size. To do that we would use something like this:

if (browser_width != width || browser_height != height)
    {
    width = min(base_width, browser_width);
    height = min(base_height, browser_height);
    scale_canvas(base_width, base_height, width, height, true);
    }

You could even use the median() function instead of the min() function to set a minimum and maximum scale for the game canvas. Play around with different values here in this object and for the room size, then test the game while dragging the browser edges to different sizes to see how all this works together.


SCALING WITH VIEWS

We have seen that it is a simple procedure to scale the game canvas to the browser width and height so that no matter how the user resizes the browser, the game room will still be visible. However, what about when using viewports and cameras? Assuming that you are only using one view, this is a relatively simple thing to deal with, and you can build on top of the code previously given for scaling the room.

To start with we would need to change the Create Event code slightly to look like this:

base_width = 640;
base_height = 480;
width = base_width;
height = base_height;

Here the base width is now set to the size that we want the viewport to be (as set in the room editor, in this case, it's 640x480). We can then use the room scaling code given above in the step event as normal for setting the window size and to get the correct viewport size, we add a little extra into the scaling script so it now looks like this:

/// @function                       scale_canvas(base width, base height, current width, current height, center);
/// @param {int}    base width      The base width for the game room
/// @param {int}    base height     The base height for the game room
/// @param {int}    current width   The current width of the game canvas
/// @param {int}    current height  The current height of the game canvas
/// @param {bool}   center          Set whether to center the game window on the canvas or not

var _bw = argument0;
var _bh = argument1;
var _cw = argument2;
var _ch = argument3;
var _center = argument4;
var _aspect = (_bw / _bh);

if ((_cw / _aspect) > _ch)
    {
    window_set_size((_ch *_aspect), _ch);
    }
else
    {
    window_set_size(_cw, (_cw / _aspect));
    }
if (_center)
    {
    window_center();
    }

view_wport[0] = min(window_get_width(), _bw);
view_hport[0] = min(window_get_height(), _bh)
surface_resize(application_surface, view_wport[0], view_hport[0]);

That about covers all you need to know for scaling the game canvas to a fixed size, with or without viewports. However, that is not the end of our article as we have one final scaling trick up our sleeves for HTML5... Scaling the game to fit the full browser window!


FULLSCREEN SCALING

This final section of the tech blog dedicated to the HTML5 target covers one further way to scale the game canvas... Fullscreen! Now, you cannot set fullscreen mode directly through GameMaker Studio 2 as this is browser dependent and requires implicit user input. However you can scale the canvas to fill the browser, and so simulate a fullscreen app.

Before getting started it's important to realise that the minimum view width and height cannot be fixed like they were previously since the resized canvas could be any width or height. All we can do is set a value whereby the view will not get any smaller but start to be cropped. Think about it like this... the browser can be stretched to fit any proportion from a very narrow rectangle to a perfect square, and so we have to take this into account and create a "best fit" that will both crop or expand the view as well as shrink or grow the canvas.

To get this working correctly, we have to choose a single value that will be the minimum width or height that the viewport will be scaled to. To see why, take a look at this diagram:

undefined

To set this up requires another script, which we'll call canvas_fullscreen(). As you will see, it's remarkably similar to previous scripts in that it is all down to the aspect ratio that we use. However, for this, we need the aspect ratio of the browser, as that is what will determine whether the view is scaled to the base size along its width or its height. The necessary code to add to the script is:

/// @function               canvas_fullscreen(base)
/// @param {int}    base    The base value for scaling on both axis

var _base = argument0;
var _bw = browser_width;
var _bh = browser_height;

view_wport[0] = _bw;
view_hport[0] = _bh;
window_set_size(_bw, _bh);
window_center();

var _aspect = (_bw / _bh);
if (_aspect < 1)
    {
    var _vw = _base * _aspect;
    var _vh = _base;
    }
else
    {
    _vw = _base;
    _vh = _base / _aspect;
    }

camera_set_view_size(view_camera[0], _vw, _vh);
surface_resize(application_surface, view_wport[0], view_hport[0]);

The argument passed to the script will be the base size that we set for either the horizontal or vertical axis, and to use the script we'd have a Create Event like this:

base_size = 512;
width = browser_width;
height = browser_height;
canvas_fullscreen(base_size);

And then in the Step Event:

if (browser_width != width || browser_height != height)
    {
    width = browser_width;
    height = browser_height;
    canvas_fullscreen(base_size);
    }

And that's about it! With this code your game will occupy the full browser width and height, cropping and scaling to suit the current aspect ratio of the browser itself. If you'd like to see how all this hangs together, you can download a test app "HTML5_Scaling_Demo.yyz" and play with the settings.