How do I scale my game in Phaser?

How do I scale my game in Phaser?

One of the many questions I’ve seen asked is “How do I scale my game in Phaser?”. I have seen a lot of different answers to this query. I’m not saying any of the other answers you will find out there are wrong. What I will say, is this is how I do it, and that has worked well for me so far. One of the nice things about my job (at gaiaonline.com) is that we get hundreds of thousands of plays on the games and our users are not shy about complaining. When there are problems I have been able to refine my code based on their feedback.

Why won’t my game fit on my phone?

The problem lies not within Phaser itself but rather the different sizes of phone screens. Those of us who have been making web games for some time are used to just building a game that will fit most monitors that were made in the last 10 years. For years the standard was 800 x 600. Then came mobile. Instead of our work area getting bigger it shrank. We now had dozens or screen sizes to contend with.

So what code do I use to scale my game?

Unfortunately, there is not one single line of code to make your game responsive. There are two steps I follow to making a game that will run on desktop and most phones.

  1. planning
  2. maths

*(maths, my fellow Americans, is how the rest of the English-speaking world refers to math. You’ll get used to it)

Making the canvas fit the phone

For a desktop game in portrait mode, I usually use

game = new Phaser.Game(480, 640, Phaser.AUTO, "ph_game");

For a mobile portrait mode, I set the dimensions dynamically

game = new Phaser.Game(window.innerWidth, window.innerHeight, Phaser.AUTO, "ph_game");

You can see more about this and about how to detect mobile in the starter snippets or my Phaser Templates

Planning Out for scaling

The size of a game will vary on each different device, but we do have some constants to work with. From the start of planning a game in my head, I start thinking about where each part will go in relation to the borders of the game. One of the things I rarely do is to set a stationary sprite, image or a textfield by a number. For example instead of

this.scoreText.x=240;

which would place the text in the middle of a game 480 pixels wide. I would use half the width

this.scoreText.x=game.width/2;

In my opinion, to make the move from desktop to mobile we need to start thinking in terms of ratios and borders rather than static values.

Positioning Formulas

Here are some of the formulas I use to position sprites.

This assumes the sprite has an anchor of 0.5, on both x and y anchors.

Center

obj.x = game.width / 2;
obj.y = game.height / 2;

Align to Bottom

obj.y = game.height - obj.height / 2;

Percentage from top- where the variable percent is a number from 0 to .99

obj.y=game.height*percent;

Percentage from bottom

obj.y = game.height - (game.height * percent);

Percentage from Right

obj.x = game.width - (game.width * percent);

Percentage from Left

obj.x = game.width * percent;

Percentage from Center

obj.x = game.width / 2 - (game.width * percent);
obj.x -= obj.width / 2;

To position sprites with an anchor int the top left corner, or to position groups I subtract half of the width of the sprite/group

Center a group

obj.x = game.width / 2 - obj.width / 2;
obj.y = game.height / 2 - obj.height / 2;

Scaling

I try to keep scaling to a minimum in my games, but sometimes, especially for the Ipad it is necessary.

I like to base the scaling using the width of the game as a constant.

First I make the game for desktop and get the sprite to game width ratio

console.log(obj.width/game.width);

Then I set the sprite by that ratio, on the desktop game this will have no effect

scaleToGameW(obj,percent)
    {
    	obj.width=game.width*percent;
    	obj.scale.y=obj.scale.x;
    }

obj.scale.y=obj.scale.x will keep the object proportional. For more about this see Scaling Objects Proportional in Phaser.

Here is an example:

I want to put three animals standing on the ground. I also want the sun in the middle of the game, and I want this to look right on every device.

How do I scale my game in Phaser?

Here is the code I will use to do that

var StateMain = {
    preload: function() {
        game.load.image("cow", "images/cow.png");
        game.load.image("elephant", "images/elephant.png");
        game.load.image("lion", "images/lion.png");
        game.load.image("sun","images/sun.png");
        game.load.image("ground", "images/ground.png");
    },
    create: function() {

    	//make the sky blue
    	game.stage.backgroundColor="#007fff";

    	this.ground = game.add.sprite(0, 0, "ground");
        this.elephant = game.add.sprite(0, 0, "elephant");
        this.cow = game.add.sprite(0, 0, "cow");
        this.lion = game.add.sprite(0, 0, "lion");
        this.sun=game.add.sprite(0,0,"sun");
        
        this.ground.anchor.set(0.5,0.5);
        this.elephant.anchor.set(0.5,0.5);
        this.cow.anchor.set(0.5,0.5);
        this.lion.anchor.set(0.5,0.5);
        this.sun.anchor.set(0.5,0.5);

        //use getScaleToGameW 
        //in desktop mode to get your percentages to 
     	//use in this.scaleToGameW
     	//this.getScaleToGameW(this.sun);
        
        //set the percentages
     	this.scaleToGameW(this.cow,.13);	
     	this.scaleToGameW(this.lion,.11);
     	this.scaleToGameW(this.elephant,.13);
     	this.scaleToGameW(this.sun,.27);

     	
     	
     	//stretch the ground to match the width of the game
        this.scaleToGameW(this.ground,1);

        //center the sun
        this.center(this.sun);

        //put the ground at the bottom
        this.alignToBottom(this.ground);
        this.centerH(this.ground);

        //put the cow on the bottom
        //and 10 percent from the left
        this.alignToBottom(this.cow);
        this.fromLeft(this.cow,.1);

        //put the lion on the bottom
        //and in the center of the screen
        this.alignToBottom(this.lion);
        this.centerH(this.lion);

        //put the elephant at the bottom
        //and 10 percent from the right
        this.alignToBottom(this.elephant);
        this.fromRight(this.elephant,.1);

    },
    update: function() {},
    getScaleToGameW(obj)
    {	
    	console.log(obj.width/game.width);
    },
    scaleToGameW(obj,percent)
    {
    	obj.width=game.width*percent;
    	obj.scale.y=obj.scale.x;
    },
    center: function(obj) {
        obj.x = game.width / 2;
        obj.y = game.height / 2;
    },
    centerH: function(obj) {
        obj.x = game.width / 2;
    },
    centerV: function(obj) {
        obj.y = game.height / 2;
    },
    centerGroup: function(obj) {
        obj.x = game.width / 2 - obj.width / 2;
        obj.y = game.height / 2 - obj.height / 2;
    },
    centerGroupH: function(obj) {
        obj.y = game.height / 2 - obj.height / 2;
    },
    centerGroupW: function(obj) {
        obj.x = game.width / 2 - obj.width / 2;
    },
    alignToBottom: function(obj, offset = 0) {
        obj.y = game.height - obj.height / 2;
        obj.y+= offset;
    },
    fromBottom: function(obj, percent, offset) {
        obj.y = game.height - (game.height * percent);
        obj.y -= offset;
    },
    fromTop:function(obj,percent,offet=0)
    {
    	obj.y=game.height*percent;
    	obj.y+=percent;
    },
    fromRight: function(obj, percent, offset = 0) {
        obj.x = game.width - (game.width * percent);
        obj.x -= offset;
        //obj.x -= obj.width / 2;
    },
    fromLeft: function(obj, percent, offset = 0) {
        obj.x = game.width * percent;
        obj.x += offset;
    },
    fromCenterH(obj, percent) {
        obj.x = game.width / 2 - (game.width * percent);
        obj.x -= obj.width / 2;
    },
    fromCenterV(obj, percent) {
        obj.x = game.width / 2 - (game.width * percent);
        obj.x -= obj.width / 2;
    }
}

There are some extra functions in there not used in the example, that I thought you might find useful. Play around with them 🙂

Click here to open the result in a new tab. Then use the mobile testing on the developer console(press f-12) on Chrome to switch between different devices.

Now I am not saying that this will work for every single situation. That is why planning is crucial before you start coding your game! This method has worked well for me and I hope you find it useful.

13 thoughts on “How do I scale my game in Phaser?”

    1. Yes, I’ve done that for a long time. The problem is that if you are using assets that go off the screen such as a scrolling platform game, game.world.centerX is the center of the entire contents, not just the screen.

  1. Centering works for images, but for text, the first letter starts at the center and all the rest is push off to the right. How to fix it so the whole text is centered?

    1. You need to set the origin for your text to center. Text is left-top aligned by default.

      Default
      myTextObject.setOrigin(0,0);

      Centered
      myTextObj.setOrigin(0.5,0.5);

  2. Hello,
    Thanks a ton for being so willing to share your knowledge and resources! Let my preface by saying that knowledge wise, I’m very much a novice but I have been successful in achieving much of my game creation goals simply by following tutorials (many of which have been yours). That being said, when creating games with Phaser 2 they seem to automatically display the way that I want them to on all devices (the screen and objects shrink but display as they would on my desktop and thus play the same). I’m in the process of learning Phaser 3 using your tutorials and resources which seem very much worth my time but using some of your templates I can’t seem to duplicate the display effect described above. It seems no matter what I try the screen and objects don’t shrink and display the same size. With my limited knowledge I would prefer to continue using your templates but is there a way to disengage that “align” feature as even removing all references to “align” and “Align.scaleToGameW” don’t seem to work.

    1. Hi Shane,

      I’m not sure what you were using in Phaser 2 to scale. I think that the scale manager was different. I never used it much. You can certainly use Phaser and even some of my templates without the Align features, but some are built with that dependency. Which template are you using? I’m sorry the functions don’t seem to work, but I don’t think you should give up on it just yet. Have you tried using a basic example?

      The functions are based on Maths and percentages, and I’ve used those classes with Pixi and other libraries as well. Can you send me some of your code and I’ll try to help you?

      1. Thanks for replying so fast – I think I must be using the templates with the Align features built in. I love the majority of the other built in features so I was trying to void that one feature. I probably will just need to copy and paste the desired features into a more basic template. I actually want the cloud to get bigger and smaller, like it did in the link that you attached, for some scenes because otherwise my art images and text don’t fit in the “sceneTitle” for example. The “typewriter” text stays the same size for the mobile devices as it does for the desktop so it doesn’t fit.

        1. Can you show me the code you are trying to use? The scaleToGameW function is simply getting the game’s width and resizing the game object to a percentage of that.
          obj.displayWidth = scene.game.config.width * per;
          obj.scaleY = obj.scaleX;

          1. I’m using the “Ultimate Game Parts Template” along with the “Type Writer” text effect. The game width is 1200 with a height of 750. Here is the code for the “sceneTitle”:
            import {
            BaseScene
            } from “./baseScene”;
            import {
            FlatButton
            } from “../common/ui/flatButton”;
            import {
            TypeWriter
            } from “../common/ui/typewriter”;

            //
            //
            //
            export class SceneTitle extends BaseScene {
            constructor() {
            super(‘SceneTitle’);
            }
            preload() {
            super.preload();
            }
            create() {
            super.create();
            //
            //
            // uncomment to turn on music
            // this.mm.setBackgroundMusic(“backgroundMusic”);
            //
            this.setBackground(‘sky’);
            //
            //
            this.makeAlignGrid(11, 11);
            // this.aGrid.showNumbers();
            //
            //
            //
            // this.placeImage(‘title’, 27, .8);
            this.placeText(“Game Title”,27,”TITLE_TEXT”);
            //
            //
            //
            // let buttonStyle = this.textStyles.getStyle(TextStyles.BUTTON_STYLE);
            let btnNext = new FlatButton({
            scene: this,
            textStyle: ‘BUTTON_STYLE’,
            key: “button”,
            text: “START GAME”,
            callback: this.startGame.bind(this)
            });

            let startscreen = this.add.image(600,295,”chickencatsgamepic”);

            var myText = “A family of chickens and cats share ups and downs, smiles and frowns, and a whole lot of whacky adventures together. Twin Chickencats Shanebob and Mikey face all sorts of adversity with their pals at Animal Crossing Elementary. The odds are stacked against them as their older brother, Jesse, and his band set out to torment them on a recurring basis while their father, Principal Ron, is constantly on their case. Luckily, they receive recluse from their hardships at school regularly, in favor of new ones in distant kingdoms and times right down the hall…”;
            var style = {
            ‘color’: ‘white’,
            ‘fontSize’: ’24px’,
            ‘wordWrap’: {
            ‘width’: this.sys.game.config.width
            }
            }
            this.tw = new TypeWriter({
            ‘scene’: this,
            ‘text’: myText,
            ‘speed’: .5,
            ‘style’: style
            });

            this.aGrid.placeAtIndex(104, btnNext);
            //
            //
            //
            //
            //
            //
            this.makeUi();
            // this.placeText(“Test Me!!”,49,”frost”);
            }
            makeUi() {
            super.makeSoundPanel();
            super.makeGear();
            }
            startGame() {
            this.scene.start(“SceneMain”);
            }
            update() {}
            }

  3. I don’t see you scaling the typewriter text anywhere. It isn’t automatic. You have to call it.

    Try this.
    import {
    Align
    } from “../common/util/align”;

    Align.ScaleToGameW(this.tw.text1,.5,this);

Leave a Comment