LibGDX project setup using the Gradle application

26. June 2014

 

Since LibGDX 1.1, there has been a massively improved way of creating a LibGDX project.  This document looks at how you get up and started using the setup application.

 

First thing you have to do is download it.  Head on over to the LibGDX download page and download Setup App.

 

Libgdx1

 

Now that you’ve downloaded the file gdx-setup.jar, double click it and say OK to any security questions.  If it doesn’t load when you double click it, you either don’t have Java installed ( you need a JDK to work with LibGDX ) or your file extensions handling for .java files are broken.  Assuming everything worked correctly the setup app should have loaded.

 

Here is an example I’ve configured already:

Libgdx2

 

One important thing is you need to have the Android SDK installed as well.  Google have made the process rather confusing, as their default download is bundled with Eclipse.  If you are intending to use a different IDE, the download you want is under “Download for other Platforms”, which is an extremely stupid name…  anyways, you need to have the Android SDK ( Android Build Tools version 19.1 as of time of writing, keep in mind you have to configure the Android SDK after downloading it ) installed as you have to provide the path to where you installed it.  

 

Otherwise it’s the usual suspects here, your project name, package and class.  Keep in mind they follow Java variable naming conventions, so for example, no spaces and mostly just alphanumeric characters.  LibGDX version allows you to choose which version of LibGDX to use, although oddly enough in every release there has only ever been the option for the most recent release.

 

In the Sub Projects section, you are deciding what targets you want to support.  If you aren’t on a Mac, iOS will not be an option.  

 

Extensions are where you configure which of the LibGDX extensions you want installed/configured.  Bullet is a physics engine, free type is a font engine, tools give you the various command line tools that are bundled with LibGDX ( I believe ), Controllers is gamepad support, Box2d is a 2D physics engine while Box2dlights is… well I have no idea what that is.

 

Now the part that is of critical importance is “Advanced”.  In all honest I think the “Advanced” options are far more important than the extensions.  I would actually instead suggest making the Setup app a 2 step process and make Advanced a mandatory process.  Anyways enough about my opinions, click advanced!

LibGdx3

 

This is where you pick what kind of IDE you use.  For each you intend to use, tick the checkbox and it will generate the appropriate project files.  In this case I am going to be using IntelliJ IDEA, so I will tick next to IDEA.  The Maven mirror box is probably something you will never use so let’s ignore it.  Offline mode is a bit more difficult to decide.  Basically the project you create will automatically go online and figure out what dependencies your project has and make sure your project is always up to date.  If you aren’t going to have an internet connection reliably or yours is ungodly slow, you may consider ticking Offline Mode.  Otherwise you are probably best served leaving it unticked.  Now click Save.

 

Now back in the Setup app, click Generate:

LibGdx4

 

Now the setup app will churn away for a while, downloading required files and configuring your project. If there is something wrong with your configuration, you will be warned.  On my PC using my cell connection the process took about a minute.  If successful it should look like this:

LibGDX5

 

There is still some configuration to be done for running each project type in your IDE.  I have already covered that process in IntelliJ right here.  You only need to read the last half of that link.

 

Programming ,




Adventures in Phaser with TypeScript–Handling Keyboard Input

24. June 2014

 

 

In the previous part we looked at handling graphics in Phaser, now we are going to look at handling input.  This part is going to be code heavy and fairly light on description.  Look to the code comments for more details.

As is pretty common with game frameworks, there are a number of different ways to handle input and a number of different devices, so lets get started!

 

Using the cursor keys and polling for input

 

/// <reference path="phaser.d.ts"/>

// Demonstrate the use of arrow keys in a Phaser app
// This application demonstrates creation of a Cursor and polling for input
class SimpleGame {
    game: Phaser.Game;
    jetSprite: Phaser.Sprite;
    cursors: Phaser.CursorKeys;

    constructor() {
        this.game = new Phaser.Game(640, 480, Phaser.AUTO, 'content', {
            create: this.create, preload: this.preload,
        update: this.update});
    }

    preload() {
        var loader = this.game.load.image("jet", "jet.png");
    }

    create() {
        var image = <Phaser.Image>this.game.cache.getImage("jet");
        this.jetSprite = this.game.add.sprite(
            this.game.width / 2 - image.width / 2,
            this.game.height / 2 - image.height / 2,
            "jet");

        // create the cursor key object
        this.cursors = this.game.input.keyboard.createCursorKeys();
    }

    update() {
        // Update input state
        this.game.input.update();

        // Check each of the arrow keys and move accordingly
        // If the Ctrl Key + Left or Right arrow are pressed, move at a greater rate
        if (this.cursors.down.isDown)
            this.jetSprite.position.y++;
        if (this.cursors.up.isDown)
            this.jetSprite.position.y--;
        if (this.cursors.left.isDown) {
            if (this.cursors.left.ctrlKey)
                this.jetSprite.position.x -= 5;
            else
                this.jetSprite.position.x--;
        }
        if (this.cursors.right.isDown) {
            if (this.cursors.right.ctrlKey)
                this.jetSprite.position.x += 5;
            else
                this.jetSprite.position.x++;
        }
    }
}

window.onload = () => {
    var game = new SimpleGame();
};

 

When you run this code the familiar jet sprite is rendered centered to the canvas. You can then use the arrow keys to move the fighter around.  As you can see, in the state for each key is information on modifier keys like Control and Alt.  Polling for input ( that is, checking status each call to update ) is a valid way of controlling a game, but sometimes you instead want to respond to input as it arrives.  Let’s look now at an example of event driven keyboard handling:

 

/// <reference path="phaser.d.ts"/>

// Demonstrate keyboard input handling via callback
class SimpleGame {
    game: Phaser.Game;
    jetSprite: Phaser.Sprite;
    W: Phaser.Key;
    A: Phaser.Key;
    S: Phaser.Key;
    D: Phaser.Key;

    constructor() {
        this.game = new Phaser.Game(640, 480, Phaser.AUTO, 'content', {
            create: this.create, preload: this.preload
        });
    }

    preload() {
        var loader = this.game.load.image("jet", "jet.png");
    }

    moveLeft() {
        this.jetSprite.position.add(-1, 0);
    }
    moveRight() {
        this.jetSprite.position.add(1, 0);
    }
    moveUp(e: KeyboardEvent) {
        // As you can see the event handler is passed an optional event KeyboardEvent
        // This contains additional information about the key, including the Control
        // key status.
        // Basically if the control key is held, we move up or down by 5 instead of 1
        if (e.ctrlKey) 
            this.jetSprite.position.add(0, -5);
        else
            this.jetSprite.position.add(0, -1);
    }
    moveDown(e: KeyboardEvent) {
        if (e.ctrlKey)
            this.jetSprite.position.add(0, 1);
        else
            this.jetSprite.position.add(0, 1);
    }

    create() {
        var image = <Phaser.Image>this.game.cache.getImage("jet");
        this.jetSprite = this.game.add.sprite(
            this.game.width / 2 - image.width / 2,
            this.game.height / 2 - image.height / 2,
            "jet");

        // Create a key for each WASD key
        this.W = this.game.input.keyboard.addKey(Phaser.Keyboard.W);
        this.A = this.game.input.keyboard.addKey(Phaser.Keyboard.A);
        this.S = this.game.input.keyboard.addKey(Phaser.Keyboard.S);
        this.D = this.game.input.keyboard.addKey(Phaser.Keyboard.D);

        // Since we are allowing the combination of CTRL+W, which is a shortcut for close window
        // we need to trap all handling of the W key and make sure it doesnt get handled by 
        // the browser.  
        // Unfortunately you can no longer capture the CTRL+W key combination in Google Chrome
        // except in "Application Mode" because apparently Google thought an unstoppable un prompted
        // key combo of death was a good idea...
        this.game.input.keyboard.addKeyCapture(Phaser.Keyboard.W);

        // Wire up an event handler for each K.  The handler is a Phaser.Signal attached to the Key Object
        this.W.onDown.add(SimpleGame.prototype.moveUp, this);
        this.A.onDown.add(SimpleGame.prototype.moveLeft, this);
        this.S.onDown.add(SimpleGame.prototype.moveDown, this);
        this.D.onDown.add(SimpleGame.prototype.moveRight, this);
    }
}

window.onload = () => {
    var game = new SimpleGame();
};

 

As you can see, you can also create Phaser.Key objects and attach onDown event handlers ( technically Signals ) to each.  Of course you can reuse the same handler for multiple keys.  A couple key things to notice here… unlike the previous example, holding down a key will not cause continuous movement.  You must press and release the key over and over.  If you want constant movement, either use a polling method, use and action instead of updating each frame, or add some logic to move until the key is released.

 

The other thing to be aware of here is the use of the CTRL+W combination and addKeyCapture().  addKeyCapture() allows you to prevent the event from bubbling up, so once you’ve handled the key combination, it’s done.  Otherwise it would keep being passed up, either to other objects in the scene, or to the browser itself.  You can also use addKeyCapture to prevent default web behavior, such as scrolling when SPACE is pressed.

 

Programming , , , ,




Adventures in Phaser with TypeScript–Graphics Time!

9. June 2014

 

 

I’ve done a number of these walk through type tutorials using many different languages/libraries and there is one common traffic trend.  People LOVE reading about graphics.  In every single example the post I do about graphics always seems to draw the most traffic.  I guess we just love drawing stuff on screen.  Now for the good part, Phaser is good at it and makes it really all quite easy.

 

Loading and adding a sprite

 

Back in the previous post I actually jumped the gun a bit and showed preloading and rendering sprites.  Since so many people jump ahead straight to the graphics post, I’ll review the process.

 

/// <reference path="phaser.d.ts"/>
class SimpleGame {
    game: Phaser.Game;
    titleScreenImage: Phaser.Sprite;

    constructor() {
        this.game = new Phaser.Game(800, 600, Phaser.AUTO, 'content', { create: this.create, preload: this.preload });
    }
    preload() {
        this.game.load.image("title", "TitleScreen.png");
    }
    create() {
        this.titleScreenImage = this.game.add.sprite(0, 0, "title");
    }
}

window.onload = () => {
    var game = new SimpleGame();
};

 

The key concepts to be aware of here is preloading assets using game.load methods, where you pass in the filename as well as a unique string key that you will use to access the asset.  Then in create you can see this in action, where we add a sprite to the game using game.add.sprite, using the key “title” to access it.  In this case our “sprite” was a full screen image.  Now let’s look at how you can work with a sprite, this time using a slightly smaller image.

Working with sprites

 

For this section I am going to work with this sprite ( created in this tutorial series ):

jet

 

Add it to your project’s root directory.  In my case I’ve called it jet.png.  Using the above code, simply replace “TitleScreen.png” with “jet.png” and “title” with “jet” and you should see:

 

image

 

 

As you can see, our sprite is drawn at the top left corner of the screen.  That is because the value (0,0) in Phaser refers to the top left corner of the screen by default.  Let’s instead center our sprite using the following code:

 

/// <reference path="phaser.d.ts"/>
class SimpleGame {
    game: Phaser.Game;
    jetSprite: Phaser.Sprite;

    constructor() {
        this.game = new Phaser.Game(800, 600, Phaser.AUTO, 'content', { create: this.create, preload: this.preload });
    }
    preload() {
        var loader = this.game.load.image("jet", "jet.png");
    }
    create() {
        var image = <Phaser.Image>this.game.cache.getImage("jet");
        
        this.jetSprite = this.game.add.sprite(
            this.game.width / 2 - image.width / 2,
            this.game.height / 2 - image.height / 2,
            "jet");
    }
}

window.onload = () => {
    var game = new SimpleGame();
};

 

Run this code and:

image

 

We are now nicely centered, both to the window and sprite.

We have one major challenge with centering the image.  Until the sprite is created, it doesn’t have a width or height.  However, when you create the sprite you can set it’s position.  Of course it would be possible to create then move the sprite but that is hackish and could have unintended graphical problems.  Instead we can get the image we loaded using this.game.cache.getImage() then access the images dimensions.  One line of code might stand out for you here:

 

var image = <Phaser.Image>this.game.cache.getImage("jet");

 

This is TypeScript’s way of typecasting.  If you’ve worked in Java, C# or C++ you’ve no doubt encountered typescasting.  If your experience was mostly in JavaScript ( a mostly typeless language ), this might be new to you.  Basically what you are saying is “we promise the value returned by getImage() is of the type <Phaser.Image>, so make image a Phaser.Image”.  If you try to access a value or method in image that doesn’t exist in Phaser.Image, TypeScript will give you an error.

 

Positioning items in Phaser

 

When using a sprite, by default, transformations happen relative to the top left corner of the sprite.  This is why we had to subtract half to the width and height of the sprite when positioning it in the center of the screen.  Otherwise the top left corner of the sprite would be centered to the screen like this:

image

 

Sometimes however you would rather transform the sprite relative to a different point, commonly the very middle or occasionally the bottom left corner.   Fortunately there is an option for this, the anchor.  The anchor tells Phaser where to draw your Sprite relative to.  Here we set the anchor to the center of the sprite then draw it at (0,0) like so:

 

    create() {
        var image = <Phaser.Image>this.game.cache.getImage("jet");
        
        this.jetSprite = this.game.add.sprite(
            this.game.width / 2 - image.width / 2,
            this.game.height / 2 - image.height / 2,
            "jet");

        this.jetSprite.anchor.set(0.5,0.0)
        this.jetSprite.position.x = this.jetSprite.position.y = 0.0;
    }

 

And the result:

image

As you can see, draw calls for the sprite now position relative to it’s center.  Positioning sprites relative to their center is incredibly handy when it comes to rotation, while anchoring at the bottom is useful for platformers where you are aligning the sprite’s feet to the ground.  What you chose is entirely up to you.  The values passed in to anchor might be a bit confusing, as they are normalized, meaning they go from 0 to 1.  The values are all relative to the sprite itself, while (0,0) is the top left corner of the sprite, while (1,1) is the bottom right corner.  (1,0) would be the bottom left, while (0,1) would be the top right.

 

There is one important thing to be aware of here.  Anchor works relative to the source image, not the sprite itself.  Therefore if you intend to scale your sprites, instead of using anchor, you are going to want to use pivot instead.  (Until recently pivot was broken, but it appears to work now).  Pivot sets the center point of the sprite, not the image that composes the sprite.  Setting the pivot looks like this:

        this.jetSprite.pivot.x = this.jetSprite.width / 2;
        this.jetSprite.pivot.y = this.jetSprite.height / 2;

 

Again, you don’t have to set the anchor at all, but it can be useful.  Unlike anchor, pivot uses relative pixel coordinates within the sprite itself.  Therefore the mid-point is at (width/2,height/2).  Once again, (0,0) is the top left corner.

 

Simple Graphics

 

Sometimes you just want to draw primitive graphics on screen… lines, circles, boxes, that kind of stuff.  Fortunately Phaser has that built in as well in the form of the Graphics object.

 

/// <reference path="phaser.d.ts"/>
class SimpleGame {
    game: Phaser.Game;
    jetSprite: Phaser.Sprite;

    constructor() {
        this.game = new Phaser.Game(800, 600, Phaser.AUTO, 'content', { create: this.create, preload: this.preload });
    }
    preload() {
        var loader = this.game.load.image("jet", "jet.png");
    }
    create() {
        // Add a graphics object to our game
        var graphics = this.game.add.graphics(0, 0);

        // Create an array to hold the points that make up our triangle
        var points: Phaser.Point[] = [];
        // Add 4 Point objects to it
        points.push(new Phaser.Point());
        points.push(new Phaser.Point());
        points.push(new Phaser.Point());

        // Position one top left, top right and botto mmiddle
        points[0].x = 0;
        points[0].y = 0;

        points[1].x = this.game.width;
        points[1].y = 0;

        points[2].x = this.game.width/2;
        points[2].y = this.game.height;

        // set fill color to red in HEX form.  The following is equal to 256 red, 0 green and 0 blue.  
        // Do at 50 % alpha, meaning half transparent
        graphics.beginFill(0xff0000, 0.5);
        
        // Finally draw the triangle, false indicates not to cull ( remove unseen values )
        graphics.drawTriangle(points, false);

        // Now change colour to green and 100% opacity/alpha
        graphics.beginFill(0x00ff00, 1.0);

        // Draw circle about screen's center, with 200 pixels radius
        graphics.drawCircle(this.game.width / 2, this.game.height / 2, 200);
        
    }
}

window.onload = () => {
    var game = new SimpleGame();
};

 

The code is pretty heavily commented so should be self explanatory.  When you run it you should see:

image

 

 

A look behind the scenes

 

Let’s take a quick look at how graphics drawing works in Phaser.  That involves going back to this line:

this.game = new Phaser.Game(800, 600, Phaser.AUTO, 'content', {});

Here you are passing in a lot of important information.  First (and second) are the resolution of your game.  Next is the type of Renderer that Phaser should use.  We mentioned this briefly in the prior tutorial.  You have the option of WEBGL or Canvas rendering ( or headless, which means no rendering at all and is used for server side programming ).  Which you chose depends heavily on the device you are supporting.  For example, currently no iOS devices support WebGL and only the most recent version of Internet Explorer work.  By selecting AUTO you let Phaser decide based on the device you are running on.  Finally ‘content’ is the HTML ID of the DIV to render our game in.

 

You may notice scattered throughout Phaser’s code/documentation are references to PIXI.  Pixi.js is a popular WebGL 2D renderer that is able to fallback on Canvas rendering when WebGL is unavailable.  Pixi is the renderer that Phaser uses, so you will occasionally see Pixi classes inside Phaser code.

 

There is one final thing to cover about graphics before moving on, full screen and handling multiple resolutions.

 

Going Full Screen

 

Now let’s take a look at an application that can go full screen:

 

/// <reference path="phaser.d.ts"/>
class SimpleGame {
    game: Phaser.Game;
    jetSprite: Phaser.Sprite;

    constructor() {
        this.game = new Phaser.Game(640, 480, Phaser.AUTO, 'content', { create: this.create, preload: this.preload });
    }
    preload() {
        var loader = this.game.load.image("jet", "jet.png");
    }

    // This function is called when a full screen request comes in
    onGoFullScreen() {
        // tell Phaser how you want it to handle scaling when you go full screen
        this.game.scale.fullScreenScaleMode = Phaser.ScaleManager.EXACT_FIT;
        // and this causes it to actually do it
        this.game.scale.refresh();
    }
    goFullScreen() {

    }
    create() {
        var image = <Phaser.Image>this.game.cache.getImage("jet");

        // Draw the jet image centered to the screen
        this.jetSprite = this.game.add.sprite(
            this.game.width / 2 - image.width / 2,
            this.game.height / 2 - image.height / 2,
            "jet");

        // Set background to white to make effect clearer
        this.game.stage.backgroundColor = 0xffffff;

        // Add a function that will get called when the game goes fullscreen
        this.game.scale.enterFullScreen.add(SimpleGame.prototype.onGoFullScreen, this);

        // Now add a function that will get called when user taps screen.
        // Function declared inline using arrow (=>) function expression
        // Simply calls startFullScreen().  True specifies you want anti aliasing.
        // Unfortunately you can only make full screen requests in desktop browsers in event handlers
        this.game.input.onTap.add(
            () => { this.game.scale.startFullScreen(true); },
            this);
    }

}

window.onload = () => {
    var game = new SimpleGame();
};

 

The comments cover most of what’s going on, but I thought I would touch on a couple things in the above example.  First you cant simply request to go fullScreen in Desktop browsers for security reasons.  This means your game can’t simply start in full screen, you need to make the call to startFullScreen() inside an event handler.  Most commonly this will be in the form of a “Click here for FullScreen” button or link.

 

Next is the ()=> syntax, known in TypeScript as an arrow function expression (if you’ve used C#, this syntax is going to look awfully familiar to you!) and is something that should be coming in the next JavaScript version (ECMAScript 6).  It is simply a more compact form of a function expression ( no need for the word function ) that is automatically scoped to “this”.  You could have created a function like onGoFullScreen like we did for enterFullScreen.  ( Coincidentally we could have also handled enterFullScreen using an arrow function.

 

The last thing to look at is the scale mode.  In this example we used Phaser.ScaleManager.EXACT_FIT, which scales the scene up to match your resolution.  There are two other options, SHOW_ALL and NO_SCALE.  Here is the result of running the code above using each setting:

 

Phaser.ScaleManager.EXACT_FIT

EXACT_FIT

 

Phaser.ScaleManager.NO_SCALE

NO_SCALE

 

Phaser.ScaleManager.SHOW_ALL 

SHOW_ALL

 

If you have an HDTV, you can think about them this way.  EXACT_FIT is the same as Stretch mode.  It scales the scene to use as much of the screen as possible, but can result in some distortion.  NO_SCALE does nothing, it simply shows the scene un-altered, centered to the screen.  SHOW_ALL is about the equivalent of Letterbox.  Basically it fits as well as it can while maintaining the aspect ration of your original scene. 

 

Don’t worry, that’s not it for graphics, we have all kinds of things coming up…  spritesheets, effects, particles, animation, etc…  That’s just it for the foundations.

 

Programming , , , ,




TypeScript in WebStorm

2. June 2014

 

So far in working with TypeScript I’ve exclusively used Visual Studio and that hasn’t been entirely trouble free.  There are many people out there that wont have access to Visual Studio ( working on Mac or Linux perhaps? ) or simply wont want to.  Thankfully there is a great alternative, WebStorm.  Granted WebStorm isn’t free, although there is a 30 day trial.  It is however a very well spent $50 if you are working in JavaScript ( or TypeScript ).  This post looks at working in TypeScript with Webstorm.

 

First step of course it download and install WebStorm.  The trial is fully functioning by the way.

During the install, if you havent already, you will be prompted to install Java 6.  Don’t worry, WebStorm takes care of the process for you.

Next you need to install Node.  Node.js is a JavaScript environment that works outside of the browser.  I’ve worked with Node a number of times on this site.  Install Node using the default settings.

Now open up a terminal/command prompt and type npm install –g typescript

The results should look like:

image

 

This installed the TypeScript language.  We are now ready to go.

 

When you open a project with a typescript file a file watcher should kick in automatically.  If not, its easy enough to define one.

Select File->Settings.  ( This menu has a different location on MacOS I believe )

On the left hand side, locate File Watchers:

image

 

On the right hand side, if none exist for TypeScript, click plus.  If one exists, make sure its checked.

image

Then select TypeScript from the list:

image

 

Default values should be correct:

image

 

If you have any problems at this point, make sure that Node was installed correctly and that you installed TypeScript, these are the most common problems.

 

Now with a File Watcher created, whenever you save a change to a TS file, it while automoatically compile the JS file.  Like so:

image

 

From this point on you will be able to see full syntax highlighting as well as code completion:

image

 

 

Additionally, you can set a breakpoint in WebStorm:

image

 

And assuming you’ve enabled the WebStorm plugin, you can debug in Chrome:

image

 

Which then allows you to perform the standard debugging tasks in WebStorm:

image

 

If you are coming from Visual Studio, there is one major difference to be aware of.  In Visual Studio, adding a file to your project makes it available for code completion.  In WebStorm this isn’t the case.  If you include a library, such as Phaser, you need to add a reference identifier at the top of your ts file, like so:

 

/// <reference path="phaser.d.ts"/>

 

Then code completion will work properly.

Programming ,




Adventures in Phaser with TypeScript– Where did my game loop go?

29. May 2014

 

 

One thing every single game has in common is a game loop.  That said, it’s not always under your control!  Today we are going to look at how the game loop is implemented in the Phaser HTML5 game engine.

 

Pretty much every single video game ever created follows the same basic program flow:

 

Program Starts

Check Input

Update World

Draw scene

Program Exits

 

Of course this is a massive simplification ignoring things like updating physics simulations, multiple threads, streaming of assets, etc… but the basic flow is there in every game.  The three indented process, Input, Update and Draw are performed over and over in a loop, thus “game loop”.  In Phaser there is no exception, but the way it’s handled is a bit different.

 

If you’ve done any JavaScript game development before you’ve no doubt encountered requestAnimationFrame or if using an older browser setTimeout JavaScript functions.  Both perform basically the same task, they call a function once an interval, such as every 30th of a second if your game is set to run at 30fps.  This is the very heart of most JavaScript games and Phaser is no exception.  You the end developer don’t have to care about such low level aspacts though as this functionality is taken care of in the class Phaser.RequestAnimationFrame and is automatically created by Phaser.Game.  If you want to see the actual game loop driving your game though, I suppose this code snippet from RequestAnimationFrame.js is it:

 

    updateRAF: function () {

        this.game.update(Date.now());

        this._timeOutID = window.requestAnimationFrame(this._onLoop);

    }

 

As you can see, its basically just calling Game’s update() over and over.  Now if we take a look at the source code for update in Game it all becomes clear:

 

update: function (time) {

    this.time.update(time);

    if (!this._paused && !this.pendingStep) {
        if (this.stepping) {
            this.pendingStep = true;
        }

        this.debug.preUpdate();
        this.physics.preUpdate();
        this.state.preUpdate();
        this.plugins.preUpdate();
        this.stage.preUpdate();

        this.state.update();
        this.stage.update();
        this.tweens.update();
        this.sound.update();
        this.input.update();
        this.physics.update();
        this.particles.update();
        this.plugins.update();

        this.stage.postUpdate();
        this.plugins.postUpdate();
    }
    else {
        this.state.pauseUpdate();
        // this.input.update();
        this.debug.preUpdate();
    }

    if (this.renderType != Phaser.HEADLESS) {
        this.renderer.render(this.stage);
        this.plugins.render();
        this.state.render();
        this.plugins.postRender();
    }

}

 

So there is your traditional game loop, just nicely tucked away.  So then, where then does your code fit in all of this?  Remember back in the Hello World post when we created a Game instance we past in a “State” object implementing create and passed in the function this.create to be called, like so:

this.game = new Phaser.Game(800, 600, Phaser.AUTO, 'content', { create: this.create });

 

Well, that’s how we do it.  A State object has a number of functions that will be called, in this case we provide an implementation for create, now lets look at a slightly more complicated example:

 

class SimpleGame {

    constructor() {
        this.game = new Phaser.Game(800, 600, Phaser.CANVAS, 'content', {
            create: this.create, update: this.update,
        render: this.render});
    }

    game: Phaser.Game;
    textValue: Phaser.Text;
    updateCount: number;

    create() {
        var style = { font: "65px Arial", fill: "#ff0000", align: "center" };
        this.textValue = this.game.add.text(0, 0, "0", style);
        this.updateCount = 0;
    }

    update() {
        this.textValue.text = (this.updateCount++).toString();
    }

    render() {
        this.game.debug.text("This is drawn in render()", 0, 80);
    }
}

window.onload = () => {
    var game = new SimpleGame();
};

 

Here is the code running:

 

 

In this example the State object we are passing in to the Phaser.Game constructor implements create, update and render.  Create will be called once, predictably enough on creation.  Here we create a red text object like we did in the Hello World example.  This time however we keep a reference to it.  We also add a counter variable updateCount.  Each frame update() will be called, we simply increment the counter value and assign this to out text object.  Finally in render we draw our text using game.debug.text().  Phaser provides a number of convenient debug methods for dumping information on screen, either as text or graphically.  These functions however are *NOT* optimized and should not be used in production!

 

So as you can see, update works pretty much like you would expect, but instead of your game controlling the loop you implement methods in a State object that will be called by the Phaser engine.

 

Let’s look at a slightly more complex example that will probably make State objects make a bit more sense.  This is a two screen game, first there is a title sreen shown that when clicked then moves to the game state, which is the same as the above demo.  Let’s jump in with code:

 

module GameFromScratch {
    export class TitleScreenState extends Phaser.State {
        game: Phaser.Game;
        constructor() {
            super();
        }
        titleScreenImage: Phaser.Sprite;

        preload() {
            this.load.image("title", "TitleScreen.png");
        }
        create() {
            this.titleScreenImage = this.add.sprite(0, 0, "title");
            this.input.onTap.addOnce(this.titleClicked,this); // <-- that um, this is extremely important
        }
        titleClicked (){
            this.game.state.start("GameRunningState");
        }
    }

    export class GameRunningState extends Phaser.State {
        constructor() {
            super();
        }
        textValue: Phaser.Text;
        updateCount: number;

        create() {
            var style = { font: "65px Arial", fill: "#ff0000", align: "center" };
            this.textValue = this.game.add.text(0, 0, "0", style);
            this.updateCount = 0;
        }

        update() {
            this.textValue.text = (this.updateCount++).toString();
        }

        render() {
            this.game.debug.text("This is drawn in render()", 0, 80);
        }
    }

    export class SimpleGame {
        game: Phaser.Game;

        constructor() {
            this.game = new Phaser.Game(800, 600, Phaser.WEBGL, 'content');

            this.game.state.add("GameRunningState", GameRunningState, false);
            this.game.state.add("TitleScreenState", TitleScreenState, false);
            this.game.state.start("TitleScreenState", true, true);
        }

    }
}

window.onload = () => {
    var game = new GameFromScratch.SimpleGame();
};

 

And when you run it you see ( click to proceed ):

 

One thing to be aware of right away is this example should probably be split across 3 files not in a single one.  I kept them together to make following along easier.

 

Here, instead of creating a state object inline we declare two of them.  Here we are using the TypeScript ability extend to create Phaser.State derived objects as inheritance really isn’t part of JavaScript. Let’s take a quick look at what this code does, starting with SimpleGame.

 

Here instead of providing a State object to the Phaser.Game constructor inline ( in { } form ) we register 2 different states using game.state.add().  The first value is the string value we will access this state using, the second is the state itself while the final value is if you want to start the state while adding it.  Finally after adding each state we start one calling game.stat.start and pass in the key value of the state.  Yes, we could have simply added true when we added the TitleScreenState, but I think doing it long form is clearer.

 

Once our TitleScreenState starts, in preload it loads an image, then in create it adds the image as a sprite.  Finally it adds a tap handler that will be called when the screen is tapped.  Image loading, sprites and input will all be covered later.  One very important thing to understand here though is the this parameter passed in to onTap.addOnce.  The second value is the context that titleClicked will be called in.  In other words, the value of “this” within titleClicked is determined by the value you pass here.  This is one of the warts of JavaScript IMHO and I wished TypeScript fixed it, although it appears it hasn’t.  The importance here is, if you don’t pass the context into the Signal (onTap) then the called function (titleClicked) wont have access to itself!  You will then get an error that this.game is undefined.  Finally when titleClicked is called we launch the GameRunningState like we did earlier.  GameRunningState is basically just the functionality from our earlier example split out into Phaser.State form.

 

As you can see, Phaser.State objects allow you to logically split up your game functionality.  Of course you could just implement a single inline state like we did earlier and ignore them from this point on.

 

Programming , , , , ,