Saturday, May 2, 2015

Phaser tutorial: DronShooter - simple game in Typescript - Part 1

  





Previous Phaser tutorials:
Phaser tutorial: custom easing functions for tweening and easing functions with parameters
Phaser tutorial: sprites and custom properties for atlas frames
Phaser tutorial: manage different screen sizes
Phaser tutorial: How to wrap bitmap text


 In this tutorial we will create simple game with Phaser and Typescript. We will call it DronShooter and while it is simple (around 240 lines of commented source) it uses:
  • P2 physics
  • sprites and groups,
  • animations,
  • tweening with custom easing functions
  • keyboard input
 The result will look like this:

 Aim with cannon using left and right arrow. Launch missile with spacebar.


Setting project


 First we need to set our project. I am using Visual Studio 2013, but if you use any other IDE steps will be similar.
 Create new Typescript project and name it DronShooter:


 Open web.config file and add bold lines. If you do not do this, IIS server will not work with .json files - it will not return it on request as if the file did not exist. And we need this as our sprite atlas metadata are stored in .json.

<?xml version="1.0" encoding="utf-8"?>
<!--
  For more information on how to configure your ASP.NET application, please visit
  http://go.microsoft.com/fwlink/?LinkId=169433
  -->
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5" />
  </system.web>
  <system.webServer>
    <staticContent>
      <mimeMap fileExtension=".json" mimeType="application/json" />
    </staticContent>
  </system.webServer>
</configuration>

 In folder where you have Phaser installed, go into typescript subfolder and copy files p2.d.ts, phaser.d.ts and pixi.d.ts into directory of your game project where is index.html located. Also copy there phaser.js file from build folder.

 In Visual Studio right click on project name in Solution Explorer on the right and go to Add -> Existing Item:


 Add all the four files you copied into folder. After this step your project solution should look like this:


 Now, open index.html and change it to this:

<!DOCTYPE html>

<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>Dron Shooter</title>
    <link rel="stylesheet" href="app.css" type="text/css" />
    <script src="phaser.js"></script>
    <script src="app.js"></script>
</head>
<body>
    <div id="content"></div>
</body>
</html>

 In header we are referencing phaser.js engine script file and app.js, which will be our game script file. We are writing our code in Typescript - files with .ts extension, but it will be compiled into javascript and we have to reference compiled javascripts here, not source .ts files.

 Last setting step is to open app.ts file and replace generated content with this:

window.onload = () => {
    console.log("Starting ...");
};

 You can now press F5 to compile and run. It opens IE and runs game. Currently there will be only white window, but if you press F12, console window will open with text "Starting...".



Preparing assets


 Here we will take short break and prepare assets for game. We need one background image and several sprites. We want our sprites to organize in atlas. To make things simple I already created the atlas in SBC PicOpt, which is my tool for creating atlases (if interested read how to use it for older version here, now it can produce .json output for Phaser). Download the atlas here (right click and save as "atlas.png"):


 You will also need metadata for atlas in atlas.json file - download it here. These metadata contains information on every single sprite: where in atlas it is, how big it is, what is its name, ...

 Finally, right click and save background image (or you can create your own if it is 640x400). Save it as "bg.jpg":


 Copy all three files into the same folder as index.html is located.


Adding Phaser Game


 Now, we are all ready to start coding. Open app.ts again and replace our onload method with this "shell":

// -------------------------------------------------------------------------
// -------------------------------------------------------------------------
// -------------------------------------------------------------------------
class Game extends Phaser.Game {
    // -------------------------------------------------------------------------
    constructor() {
        // init game
        super(640, 400, Phaser.CANVAS, "content", State);
    }
}

// -------------------------------------------------------------------------
// -------------------------------------------------------------------------
// -------------------------------------------------------------------------
class State extends Phaser.State {

}

// -------------------------------------------------------------------------
// -------------------------------------------------------------------------
// -------------------------------------------------------------------------
window.onload = () => {
    new Game();
};

 In onload we are creating new Game object, which is instance of our Game class that derives from Phaser.Game. It will stay simple in this example and the only thing it does is it calls super constructor. Our game will have size 640x400. Renderer is Phaser.CANVAS, but you are free to change it to Phaser.AUTO - I used canvas as there are sometimes problems with debug output if renderer is WebGL (flickering, ...). Next parameter refers to our index.html file where in body section
we have this line: <div id="content"></div>. Here, on the page, the game will be placed. Last parameter is Phaser.State the game should start with. It is our custom State class that derives from Phaser.State.
 Phaser.State is important class as Phaser is checking it for existence of some methods and if they exist, Phaser will call them in appropriate time. In our simple game we will use these:
  • preload() - called in the beginning of state and we will load our assets here,
  • create() - called after preload. All assets are already in place and we can build our scene or create game objects here,
  • update() - called on every frame. Good place to read input from keyboard for us here,
  • render() - called when game renders. In Phaser you usually do not have to do much here as engine renders all objects in scene hierarchy for you. But this is right place to display some debug information over rendered scene.

 So, let's load our assets. Add preload() method to State class:

class State extends Phaser.State {

    // -------------------------------------------------------------------------
    preload() {
        // background image
        this.game.load.image("BG", "bg.jpg");
        // load sprite images in atlas
        this.game.load.atlas("Atlas", "atlas.png", "atlas.json");
    }
}

 Here you can see how to load simple image - no atlas, so no metadata required. And also how to load atlas with its .json metadata file. In both cases you are creating "Key" as the first parameter. Your asset (atlas or image) will be stored under this key inside Phaser and whenever you need to work with it you recall it through this key. The key is case sensitive!

 Add create() method to State class:

    // -------------------------------------------------------------------------
    create() {
        // background
        this.add.image(0, 0, "BG");
        // dron sprite
        this.add.sprite(320, 100, "Atlas", "dron1", this.world);
    }

 Press F5 to compile and run and you should see this:

 In code above: we created image with key "BG" and placed it on position 0,0, which is top left corner and then we created dron sprite and placed it on position 320, 100. The dron sprite is in atlas (asset with key "Atlas") and as it contains all our sprites, we have to specify which one we want to use ("dron1" here). Look into atlas.json file, locate dron1 sprite and check data for it.

 Two topics are here to mention:
  1. last parameter for dron sprite is this.world. If you omit it your sprite will be added to world by default. World is Phaser.World object which is derived from Phaser.Group. Group can contain for example sprites or other groups. If you move or rotate group, all child sprites and groups in it will move or rotate too. This is way how to build scene tree which says how looks object hierarchy. While group is non-leaf node, sprite is leaf node. There are also other leaf nodes like buttons, ... but in this simple game we will use only groups and sprites,
  2. secondly, we placed dron on x = 320, but it is little bit shifted to right. It is because sprites has something called anchor. It is point with default value 0,0 and it is top left corner of  sprite image. If we need is center dron sprite on position 320x100, we have to change code a little like this (0.5 = 50%):

        // dron sprite
        var dron: Phaser.Sprite = this.add.sprite(320, 100, "Atlas", "dron1", this.world);
        dron.anchor.setTo(0.5, 0.5);


End of Part 1


 Here ends part 1. In Part 2 we will start moving drones with custom easing function. We will call it wiggle as it nicely wiggles around some point in random like curves.