Quantcast
Channel: GameDev Academy
Viewing all articles
Browse latest Browse all 1620

Make a Mario-Style Platformer with the Phaser Editor

$
0
0

In this tutorial we create a simple platformer demo with Phaser Editor (an IDE made specially for boost Phaser games development). We focus here on the assets management and the built-in visual scene builder.

Check the final demo

We split the tutorial in sections and every section has a link to the source code used in it. If you are an used to Phaser Editor probably you would like to skip sections like the project setup and the assets loading, and go straight to the scene related stuff. You will be able to do that because, as we said, at the beginning of each section we provide a link to the source code of a project ready to start.

Clone or download the source code

To learn how to import a project open the Help > Help Contents and navigate to the Workbench User Guide > Tasks > Importing > Importing existing projects. Very important! When importing a project by default it just links to the original project, but for this tutorial force it to copy the content of the projects: set ON the Copy projects into workspace option.

We are not going to explain in depth the API and concepts of Phaser, so it requires that you first get some basic acknowledgement about Phaser states and Arcade physics. Check some resources to learn Phaser:

Table of contents

Create the project

First thing is to create the project of our game. In this article we are going to use the Empty template (File > New > Phaser Project > Empty).

Learn more about the first steps

A project created with the Empty template has the following files:

WebContent/index.html The start point, like in any other web application.
WebContent/lib/phaser.js The Phaser framework.
WebContent/js/Main.js The booting script, where the game is created
WebContent/assets/assets-pack.json A manifest of the game assets.
Design/ A folder where you can place resources that are not part of the game, like SVG files or source images.

By default the Main.js file is opened in the JavaScript editor. Note it is all about to create the game instance and add the states of the game.

You can run the project (Alt+F5), but it shows a blank screen, the game has no state defined yet.

Create the Level state

For simplicity let’s code the whole demo in a single Level state. To create the state, click on File > New > State Source File. It opens a dialog where you should set the name of the state (write Level) and the container folder for the new file (select WebContent/js).

Press Finish and it creates a new Level.js file.

Learn more about the JavaScript editor

The generated file contains the definition of a new Level prototype, with the preload, create and update methods. To include that Level state in the game, open the Main.js file and add the line:

game.state.add("Level", Level, true);

Do not forget to include the Level.js file in the index.html file, add a script tag with a reference to js/Level.js.

To test that everything is going well, you can add the following code to the create method of the Level:

this.add.text(10, 10, "hello world!", {
    fill : "#fff"
});

Then run the project to check the game is executing without errors. It should show a hello world! message.

(Import the project Step_01 to see the final result)

Load the assets

(You can start with the project Step_01)

Together with the tutorial source code we provide here, there is an Assets folder with all the images we are going to use now on. Please copy the content of that folder and paste it in the WebContent/assets folder of the game project. It should look like this:

LoadAssets_ProjectExplorer

 

In Phaser there are two main ways to load the assets, by loading every asset in the preload method, using a specific loader method (like game.load.image, game.load.spritesheet, etc…), or by declaring all the assets in a manifest file (the Asset Pack file) and load it in the preload method with a game.load.pack call.

In Phaser Editor we encourage to use the second way, we provide several tools that are integrated with the Asset Pack, like the Asset Pack editor, the Assets explorer, Preview windows, JavaScript editor, the visual level editor… almost everything.

To declare the assets in the pack, open the WebContent/assets/assets-pack.json file, it opens the Asset Pack editor. The editor has two panels, the left panel shows a tree with the sections, asset types and assets. The right panel shows the details of the selected object in the left panel. If it is a section, you can change the name, if it is an asset, it shows the asset’s properties, like key, textureUrl… it depends on the asset type.

Learn more about the Asset Pack editor.

So let’s add the assets of our demo to the pack. Check in the assets folder we have the following files:

images/BG.png The level background.
images/fufu.png A sprite-sheet of our player, a dino called Fufu. The frames have a 207×140 size.
textures/objects.png
textures/objects.json
The textures atlas containing the level items (tree, bush, fruit, etc…)
textures/tiles.png
textures/tiles.json
The textures atlas containing the level tiles (ground, grass, water, etc…)

In the Asset Pack editor, click on the Add Section button and write the name level in the input dialog. A section is a way to split the assets so in a Phaser state you can load just a subset of the assets. In our demo we just use one section called level.

LoadAssets_AssetPack1

In the left panel select the recently created section and press the Add Asset button. It opens a dialog with the type of assets we can add to the section:

LoadAssets_AssetPack2

We want to add the Dino sprite-sheet, so select the spritesheet type and press OK. It adds a new sprite-sheet under the level section and the right panel shows the details. By default it looks for a not used image and set it as the url value. We should change it to use the right fufu.png image: in the url field click the Browse button and it opens a dialog to select an image from the assets folder. In that dialog select assets/images/fufu.png.

LoadAssets_AssetPack3

You should set the right values for the rest of the required fields (key, url, frameWidth, frameHeight) and save the changes (Ctrl+S):

LoadAssets_AssetPack4

Now let’s see if all is working. Open the Level.js file and write in the preload method:

Level.prototype.preload = function() {

    this.load.pack("level", "assets/assets-pack.json");

};

It loads all the assets defined in the level section of the assets-pack.json manifest. To check the player was loaded, write in the create method:

Level.prototype.create = function() {

    this.add.sprite(10, 10, "player");

};

Finally run the project, you should see something like this:

LoadAssets_Run1

It is working, let’s add the remaining assets to the pack.

To add the BG.png image, select the level section, press Add Asset and select the type image. It adds a new image (like in game.load.image). In the details panel, set the key, the url, and save.

LoadAssets_AssetPack5

 

To add the objects.png texture atlas, select the level section, press the Add Asset button, select the atlas type and press OK. It adds a new atlas asset, set the right values on it, like in game.load.atlas. Below the fields you will find the Phaser doc related to the asset type.

 

LoadAssets_AssetPack6

Note you only need to set the key, textureURL and atlasURL.

Repeat the same steps for the tiles.png texture, and save the pack file. Remember the textures need the texture image and the texture definition (a JSON file in this case). You can hover the mouse on top of any field, it shows a tool-tip with the corresponding Phaser documentation.

All these doc is parsed from the Phaser source code, so it will be always synchronized with the Phaser version supported by the editor (we update the Phaser support at every Phaser release).

LoadAssets_AssetPack7

 

To check that all the assets are defined well, save the pack file and look into the Assets explorer, it should show all the assets, including the sprite-sheets frames and the texture sprites. Hover the mouse on top of the them to get a preview.

LoadAssets_AssetsExplorer

Something great in Phaser Editor is that it is made by using the Phaser standards. We do not add extra plugins or custom patterns. A prove of that is the assets management that we already explained here, you can use it in any Phaser game. In a completely “hand made” game or in a game that uses an external tool like Tiled, but at the same time it integrates tightly with the Phaser Editor scene builder.

(Import the project Step_02 to see the final result)

Create the scene

(You can start with the project Step_02)

At this moment we are ready to create the level, but first, lets create a new folder scenes under the WebContent/assets folder. To do this right click in the assets folder and press New > Folder. Se the new folder name and press Finish. In this scenes folder we are going to store all the scenes of the demo.

Learn more about the scene editor

In the File menu select New > Canvas File. It opens a dialog to select the name of the new scene and the container folder. As name set Scene1, as containing folder select the just created WebContent/assets/scenes folder. Press Finish and a new Scenes1.canvas will be created and opened in the Canvas editor.

CreateScene1

Now let’s add an object to the scene. In the Assets explorer, drag the player asset and drop it into the scene. It creates a player object, based on the sprite-sheet declared in the Asset Pack.

CreateScene2

In the previous illustration it shows the Properties Grid, where you can edit the properties of the selected object, and the Outline window, it shows the objects of the scene in a tree.

We saw that to add an object you should drop an asset in the scene. This asset can be taken from the Assets explorer but also from the Previews window or the Palette. We like to use the Preview windows to get the assets, just drag an asset from the Assets explorer and drop it in a Preview window. For this demo we can use this windows layout:

CreateScene3

Warning, you cannot drag the assets defined in a project and drop in the scene of other project. It is a common mistake to keep in the Preview windows the assets of another project.

Let’s add some ground. Get the tiles14 and drop it in the scene. (By the way, with the middle button you can zoom in/out and scroll the scene).

CreateScene4

That object is too small to make a ground with it, to make it larger we need to morph it into a tile sprite. By default when you drop the assets in the scene, a regular sprite is created (like in game.add.sprite), but there are other type of objects like buttons and tile sprites. For platformer games tile sprites are very important, with those objects you can create the ground, water, walls, etc.

Right click on the ground object and select Morph To > Tile Sprite.

CreateScene5

It converts the simple sprite into a tile sprite (like in game.add.tileSprite). Note in the properties grid you will be able to edit the Tile Sprite properties:

CreateScene6

To resize the sprite you can change the width and height properties in the grid, or you can resize it visually. Right click on the object and select Resize Tile Sprite (or just press the L key).

CreateScene7

It shows visual handlers that allow you to change the size of the object. Make it wider by dragging the horizontal little boxes.

CreateScene8

Now add two more objects to complete the edges of the platform.

CreateScene9

To make the objects to match one with the others, you can enable the snapping mode. In the tool bar of the scene click on the wrench icon. It opens the settings dialog, there you can set the snapping to 128×93 (the same size of the tiles). To turn the snapping ON and OFF you can press the E key.

CreateScene10

(Import the project Step_03 to see the final result)

Add the scene to the game

(You can start with the project Step_03)

We have now a small scene and we want to include it to the game and run it. Maybe you noticed that when you save the scene the first time it creates a Scene1.js file. That file contains the Phaser code of the scene, that is nothing more than a Phaser.Group. Please we encourage you to look inside that file, you will find a very familiar code. If you don’t see that WebContent/assets/scenes/Scene1.js file yet, just save the scene, it will generate the code.

Learn more about the scene editor

To include the scene in the game we should follow two steps: load the Scene1.js file and create a Scene1 object in the create method of the Level state.

We can load the Scene1.js file as any other script file, by adding it to the index.html file, but we prefer to add it through the Asset Pack as a script asset (like in game.load.script).

Then, open the assets-pack.js file and add a new script asset to the level section. Note you should provide the path to the Secen1.js file. You can use the Browse button to find it:

CreateScene11

What about the Scene1.canvas file? Do I have to load it? No, that file is used only by the editor, to generate the Phaser code of the real scene. In a production game you do not have to distribute the Scene1.canvas file.

Let’s continue with the second step, to create the scene. It is pretty straightforward, we add it as any other Phaser custom group. In the create method of the Level.js file write this:

Level.prototype.create = function() {

    this.scene = new Scene1(this.game);

};

Then run the project. The game will be shown in the default browser:

CreateScene12

It does well, but yet it is not centered and it has an ugly black background. To center it add a new init method to the Level prototype:

Level.prototype.init = function () {

    this.scale.pageAlignHorizontally = true;
    this.scale.pageAlignVertically = true;
    this.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;

};

But yet the game has a size of 1200×800 (look into the Main.js code), we should use the same size in the scene editor, to make sure everything is fitting well.

Open the scene editor. In the settings dialog (the same we shown before to change the snapping values) set the scene size to 1200 x 800. Select all the objects in the scene and drag them to the center. We want also to add a background image. From the Assets explorer drag the BG image and drop it into the scene. You can scale that image by pressing the S key, and you can send it to back by pressing the PageDown key.

CreateScene13

Save and run the game, now it should look like this:

CreateScene14

 

(Import the project Step_04 to see the final result)

Add the physics

(You can start with the project Step_04 )

What we want is to make the player (Dino) to walk and jump on top of the platforms. To do this we need to set the physics of the player and the physics of the platforms. We are going to use the Arcade physics, it is the simplest physics system in Phaser and it is the one is fully supported by Phaser Editor (it does not mean that you cannot use other physics systems like P2, you can, but the editor is not going to bring special features around it -it will in the future-).

To enable the player physics right click on it and select Arcade > Set Arcade Body (Rectangular). It adds a rectangular body to the object and shows the body boundaries with a green transparent area. You can move the body handlers to change the position and size.

AddPhysics1

Now that the player has an Arcade body, you can change many of its settings in the properties grid, just look into the Arcade section. Note that you will get tool-tips with the Phaser doc.

AddPhysics2

Remember always to save all the changes in the scene, to re-generate the code. In addition to the objects setup, you need to do some global physics initialization in your Level state. Just add following code to the end of the init method:

this.physics.startSystem(Phaser.Physics.ARCADE);
this.physics.arcade.gravity.y = 800;

Save and refresh the game in the browser, you will see how Dino is going to fall down. It happens because we set a global gravity but the Dino is not colliding with the platform.

In Phaser it is a common practice to use groups (Phaser.Group) to set the physics properties of the platforms. You put all the platforms in a single group and collide it with the player. We are going to follow the same pattern, but with a small difference, we are not going to group all the platforms, else a set of hidden objects that will make part of an invisible collision layer.

In the tiles texture there is a small red box, with the “physics” name, it is the one we are going to use to create the collision layer. So get the “physics” asset and drop it in the scene. Morph it to a Tile Sprite (press L) and re-size it to fill the platform width.

AddPhysics3

To create the collision layer, right click in the red sprite and select Group > Group Selection (or just press G). In the property grid set the name  collisionLayer and in the Group section set physicsGroup to true.

The physicsGroup property indicates that the group will be created with the game.add.physicsGroup method, in this way, you do not have to enable physics bodies in all the children, it will be done automatically by Phaser.

AddPhysics4

We are almost done. We need to set some properties to the collisionLayer in our Level state, but first, we have to make public the group, to make it accessible outside the Scene1 class. To do this, select the group in the Outline window, and in the properties grid, set the public field to true. And save, it will generate an fCollisionLayer instance field, that references to the collisionLayer.
Open the Level.js file and in the create method add this code:

Level.prototype.create = function() {

   this.scene = new Scene1(this.game);

   // set the physics properties of the collision sprites
   this.scene.fCollisionLayer.setAll("body.immovable", true);
   this.scene.fCollisionLayer.setAll("body.allowGravity", false);
   // hide all objects of the collision layer
   this.scene.fCollisionLayer.setAll("renderable", false);

};

But yet it is not going to work, we need to make the player to collide with the collision layer. By the way, you should make public the player too, it will generate an fPlayer field in the scene. So, in the update method add this code:

Level.prototype.update = function() {

   this.physics.arcade.collide(this.scene.fPlayer, this.scene.fCollisionLayer);

};

And now refresh the game in your browser, the Dino should stay on the platform.

(Import the project Step_05 to see the final result)

Add the player controls

(You can start with the project Step_05)

In Phaser it is very easy to add movements controls. In the create method of our Level state add this code:

this.cursors = this.input.keyboard.createCursorKeys();

The cursors var references an object with the the left.isDown, right.isDown and up.isDown properties, that we can test in the update method to change the player velocity. Add this code to the update method:

Level.prototype.update = function() {

    // collide the player with the platforms
    this.physics.arcade.collide(this.scene.fPlayer, this.scene.fCollisionLayer);

    if (this.cursors.left.isDown) {
        // move to the left
        this.scene.fPlayer.body.velocity.x = -200;
    } else if (this.cursors.right.isDown) {
        // move to the right
        this.scene.fPlayer.body.velocity.x = 200;
    } else {
        // dont move in the horizontal
        this.scene.fPlayer.body.velocity.x = 0;
    }

    // a flag to know if the player is (down) touching the platforms
    var touching = this.scene.fPlayer.body.touching.down;

    if (touching && this.cursors.up.isDown) {
        // jump if the player is on top of a platform and the up key is pressed
        this.scene.fPlayer.body.velocity.y = -600;
    }

};

Refresh the game in your browser, you will be able to move the player.

(Import the project Step_06 to see the final result)

Add the player animations

(You can start with the project Step_06)

Our player walks and jumps and we want to add some animations to that actions.

Learn more about the animations editor

Phaser Editor has a simple animations editor that is very easy to use (like in sprite.animations.add), just select the player and, in the property grid, click on the animations field. It opens the animations dialog.

AddPhysics5

 

AddPhysics6

Create three animations, walk, jump, and idle. The walk animation has two frames, 0 and 1, it loops with a frame rate of 4. The jump is even simpler, just add the frame 2, don’t make it to loop. And the idle animation is like the jump one, with a single frame (3) and with no looping. In a more complete game, the jump and idle animations could have more than one frame, to make it more exciting.

Now let’s improve the update method to play the animations at the right moment. Add the following code at the end:

if (touching) {
    if (this.scene.fPlayer.body.velocity.x == 0) {
        // if it is not moving horizontally play the idle
        this.scene.fPlayer.play("idle");
    } else {
        // if it is moving play the walk
        this.scene.fPlayer.play("walk");
    }
} else {
    // it is not touching the platforms so it means it is jumping.
    this.scene.fPlayer.play("jump");
}

Yet there is a detail. When the player is moved to the left it actually moves to the left, but it does not face to the left. We need to flip the player when it is moving to the left. To do this we have to update the scale (a scale.x of -1 flips the texture). Add this code at the end of the update method:

// update the facing of the player
if (this.cursors.left.isDown) {
    // face left
    this.scene.fPlayer.scale.x = -1;
} else if (this.cursors.right.isDown) {
   // face right
   this.scene.fPlayer.scale.x = 1;
}

But wait, you also have to change the anchors of the player, to make it to “turn in the place”. Go to the scene, select the player and in the property grid set the anchor.x property to 0.5. Save and refresh the game in the browser.

(Import the project Step_07 to see the final result)

Add coins

(You can start with the project Step_07)

Let’s call it coins but in this demo they are fruits. Fruits that Dino will take when touching them. Look in the objects texture there is the fruit sprite. Drop some of them in the scene.

AddPhysics7

Select the fruits and create a group with them, by pressing G. Set the name of the group to fruits and make it public. Because the player has to collide with the fruits, let’s make this group as physicsGroup in the same way we did with the collision layer. Save, a new fFruits var will be generated.

AddPhysics8

If you run the game you will see how the fruits fall down. It is because the gravity of the game, so we need to disable gravity in the fruits.

In the create method add this line:

// to keep the fruits in the air
this.scene.fFruits.setAll("body.allowGravity", false);

Ok, now we need the player to get the fruits. In the update method add this code at the end:

// catch when the player overlaps with a fruit
this.physics.arcade.overlap(this.scene.fPlayer, this.scene.fFruits,
        this.playerVsFruit, null, this);

Look we use there a function playerVsFruit that is not defined yet, so let’s add it to the Level prototype:

/**
 * @param {Phaser.Sprite} player
 * @param {Phaser.Sprite} fruit
 */
Level.prototype.playerVsFruit = function(player, fruit) {
    // when the player overlaps with a fruit
    // just remove the fruit from the game,
    // you can add a better effect later
    fruit.kill();
};

In that method we “kill” the fruit to make it go away. Look that we added some documentation to the method. The @param tag allows us to “declare” the type of the parameters, it helps the type inference machine to provide a better code auto-completion.

Run the game, now the player will get the fruits.

(Import the project Step_08 to see the final result)

Conclusions

In this article we covered some basic aspects to create a platformer level. There are other details like a bigger world, camera setup, ambient elements like grass, trees, multiples planes to give a sense of depth and maybe other stuff that you can check in the CompleteDemo project. Don’t hesitate to run it and look into the code.

Art assets used in this article

 


Viewing all articles
Browse latest Browse all 1620

Trending Articles