Explore Free Phaser 2 Tutorials – GameDev Academy https://gamedevacademy.org Tutorials on Game Development, Unity, Phaser and HTML5 Thu, 23 Feb 2023 21:14:30 +0000 en-US hourly 1 https://wordpress.org/?v=6.1.1 https://gamedevacademy.org/wp-content/uploads/2015/09/cropped-GDA_logofinal_2015-h70-32x32.png Explore Free Phaser 2 Tutorials – GameDev Academy https://gamedevacademy.org 32 32 How to Create a Multi-Platform Idle Clicker Game with Phaser https://gamedevacademy.org/phaser-tutorial-how-to-create-an-idle-clicker-game/ Thu, 23 Jun 2022 13:52:49 +0000 https://gamedevacademy.org/?p=2642 Read more]]> Since the dominance of mobile games in the industry, no genre is more popular than the idle clicker.

In this tutorial, we’re going to use the well-established Phaser 2 framework – which offers cross-platform capabilities – to build an idle clicker game where you “attack” monsters to progress in the game. Of course, we’ll also set up the ability to buy auto-clickers that will “attack” monsters for you as well.

If you’re ready to explore this in-demand genre, let’s learn!

What is an idle click game?

Also known as clicker and incremental games, these type of games have you clicking something repeatedly or idling to gain some form of currency (e.g. cookies, money, energy) which you then use to buy upgrades. It’s a very simple concept at the core, but quite addictive!

Clicker games were first made popular in 2013 with a game called Cookie Clicker. Since then many games have been created in this genre, the themes and flavor of these games vary widely. From cookies to fantasy rpg, sci fi, farming, sand castles, etc.

One such clicker game that I’ve played quite a bit is Clicker Heroes, it’s a fantasy RPG style game where you click various monsters to progress. In this tutorial, we are going to build the foundations of a clicker game similar to Clicker Heroes that you can build upon and add your own style and flair.

Screenshot of Clicker Heroes game

Tutorial source code

You can download the tutorial source code here.

BUILD GAMES

FINAL DAYS: Unlock 250+ coding courses, guided learning paths, help from expert mentors, and more.

Getting started

Source Control

The first thing that I do when starting any project is create a folder, and initialize it for git source control. If you don’t already have git, you can download it for your OS from the official site. With any software development, it is critical to have backups. Using source control, specifically git, is a much more robust and safe solution than simply copying or zipping your files periodically. It’s also important to do micro commits, save your progress in very small increments so that you can roll back to any point if you find that you’ve added some new code that is breaking everything. Also it prepares your codebase automatically for upload to a service like github or bitbucket. There are many things beyond simply committing your code that you can do with git, if you are new to git I encourage you to checkout the Git and Github Fundamentals course at Zenva Academy.

After installing git for your system, open the folder you created in a command window, and simply type git init  and it will be ready to go.

Gathering Art

We need to get some sprites for the monsters. A great site to find free art that you can use for your projects is OpenGameArt.org. Much of the artwork is either public domain or licensed to the Creative Commons. A quick search and I’ve found a resource with a variety of monster sprites. This particular set is licensed under CC BY SA 3.0 which basically means that you must give credit to the original authors, and any modifications you make must be shared under the same license. There are other licensing options available to artists, and some do not allow the use of the resources in commercial applications, so be sure to check the licensing on the site.

OpenGameArt.org website with CC-BY-SA 3.0 license highlighted

The monster images that I’ve chosen come in various sizes, each with 4 frames representing various damage states. For this game, we don’t really need the extra damage states, so I have cropped all of the images to just the first frame. For the purposes of this tutorial, I think that 1 image per monster is all that we’ll need. It would be nice if these monsters were animated, but the single image works well for a placeholder right now.

In addition to the monsters, we’ll need some rpg icons for the upgrades and loot. It’s not likely that we’ll use all 496 images in this set, but we can prune the collection later before we are ready to release of the ones that we don’t use. We’ll also need something to use as a background for our world, this forest scene will do nicely.

You’ll find all of the sprites in the assets/images folder of the companion source code to this project. If you’re downloading your own selection of images to use, place them in there as well.

Reminder: Once you’ve added your files, go ahead and commit them to source control.

Setup Phaser

You’ll need to download Phaser, you can either clone the github repo or download the release or use something like Bower to install it. Phaser games are web based games, so first we need a HTML page to host it. Create a file called index.html in the root of your project folder and put this for the contents.

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Click of the Titans</title>
        <style>body {margin: 0;padding: 0;}</style>

        <script src="lib/phaser.min.js"></script>

        <script src="src/game.js"></script>
    </head>
    <body>

    </body>
</html>

Reminder: micro commits, commit your index.html file right now!

You may have noticed that we added a reference to game.js located in the src folder. We don’t have that file yet, let’s create it now.

var game = new Phaser.Game(800, 600, Phaser.AUTO, '');

game.state.add('play', {
    preload: function() {
        game.load.image('skeleton', 'assets/allacrost_enemy_sprites/skeleton.png');
    },
    create: function() {
        var skeletonSprite = game.add.sprite(450, 290, 'skeleton');
        skeletonSprite.anchor.setTo(0.5, 0.5);
    },
    render: function() {
        game.debug.text('Adventure Awaits!', 250, 290);
    }
});

game.state.start('play');

In Phaser, everything starts with an instance of the Game class. We are passing it the width and height of the game screen that we want as well as the renderer. Phaser supports both Canvas and WebGL based rendering, Phaser.AUTO tells it to pick based on what’s available in the browser (WebGL if available).

In the preload phase of our “play” game state we are going to load up one of our monster images so that we can have something to show other than a blank screen. Each state in Phaser has several phases in its lifecycle, and preload  is one of the first.

Next up is create , after assets are loaded, it’s safe to create sprites using them. The Sprite is one of the main game objects in Phaser, most everything that you create in the game world will generally have a sprite involved. Adding a sprite takes a few parameters: the x & y coordinates of where it should be located on the screen, and a key that can be used to reference it later. We’re also going to change the anchor for the sprite to the center of the image. The anchor is the point in space where the sprite is positioned or rotated around. By default the anchor is set to the top left most point of the image 0, 0  I ususally like to work with the anchor in the center of the image, because if I want to spin the sprite, I want it to spin around the center instead of the top left (like a wheel).

Finally, render  is one of the last phases in the lifecycle, it happens after update (we don’t need update for this game). Most of the time Phaser handles rendering internally, but for now we’ll just add some fun text to make our screen more exciting.

Reminder: now’s a great time to commit your file!

Running your game

We’re almost ready to fire up Phaser and see what we have, except that it’s not just as simple as clicking on index.html and loading it in your browser. Due to security restrictions the browser will not allow you to load assets asynchronously. For that reason you need to run a server, or load the files in a different manner. PhotonStorm has posted an article listing several options for servers, however if loading the software to run a server isn’t something that you are interested in, I have another option. If you are running Google Chrome, you can actually setup your game to run as a Chrome application quite easily. Doing this elevates your game out of the browser sandbox (and actually gives you a set of APIs to access native systems such as the file system and networking) and these restrictions no longer apply. There are however a different set of security restrictions involving resources located outside of the files packaged with the app. Depending on how you want to distribute your final product, creating a Chrome app may be a great choice. I’ll include the basic files needed to launch this as a Chrome App, if you are interested in learning more I encourage you to read more at the official documentation.

Once you launch your game, you should see this:

New Phaser game with Skeleton and "Adventure Awaits" message

Now you know that Phaser is up and running. We’ve loaded a sprite and written a bit of text to the screen! We’re almost done 🙂 … well not quite, but we’re ready to start actually making a game.

Setting the Stage

The first thing that we want to do is get rid of that boring black background and bring our world to life. In the preload  method, add all of the images that make up the forest background. There happen to be four different images for this because it is designed to be used as a parallax scrolling background. Typically this type of background is used in side scrolling platformer games, but it gives us the option of doing an animation effect later.

this.game.load.image('forest-back', 'assets/parallax_forest_pack/layers/parallax-forest-back-trees.png');
this.game.load.image('forest-lights', 'assets/parallax_forest_pack/layers/parallax-forest-lights.png');
this.game.load.image('forest-middle', 'assets/parallax_forest_pack/layers/parallax-forest-middle-trees.png');
this.game.load.image('forest-front', 'assets/parallax_forest_pack/layers/parallax-forest-front-trees.png');

In the create  method since we have 4 different images that make up the background, we’ll create a Group of TileSprite objects. Using a javascript array of the image keys, we can use the built in forEach method to quickly and elegantly create all four in the correct order.

var state = this;

this.background = this.game.add.group();
// setup each of our background layers to take the full screen
['forest-back', 'forest-lights', 'forest-middle', 'forest-front']
    .forEach(function(image) {
        var bg = state.game.add.tileSprite(0, 0, state.game.world.width,
            state.game.world.height, image, '', state.background);
        bg.tileScale.setTo(4,4);
    });

A TileSprite is a type of image that is meant to be repeated or tiled over a large area. To create one you need to pass it not only the x & y coordinates, but also a width and height for how big the area that it needs to cover should be. Just like the Sprite, you give it the image key to use. The final parameter that we pass it is our group, so that each one is automatically added to the background group. We want the background to cover the whole screen, so we’ll pass in the game world’s width and height. Also, in this case, our image isn’t really meant to be tiled like a mosaic, so we’ll scale the tiling so that it looks more like one image (play with the scale numbers to see what I mean about the tiling).

Let’s take a moment to talk about the group that we created. Groups are an extremely powerful feature of Phaser that are capable of a whole lot more than just the name suggests. At the very base level, they act as a collection, sort of like an array, and they have several methods available for traversing and manipulating the items in the collection. Another important aspect of groups is that the children of the group are positioned, rotated, and scaled all relative to the group itself. If we set group.x = 10; then it will move all of the children over by 10 as well. The position of the children is relative meaning that if a child item also has it’s x coord set to 10, then it will actually be placed at x 20 on the screen (assuming that the group itself is not a child of another parent that isn’t at 0,0). We will use groups extensively in our game and I encourage you to read the documentation to find out more about all of the methods and properties that are available.

Reminder: time to commit your files!

The Army of Darkness

After setting the stage, the next thing we need is something to attack. Time to unleash the horde of monsters that we’ve collected. In order to be able to use all of our monsters, we need to load each image. Let’s change the preload  section of our play  state to do just that. Each one needs a key to reference it by, and the path to the image file.

    this.game.load.image('aerocephal', 'assets/allacrost_enemy_sprites/aerocephal.png');
    this.game.load.image('arcana_drake', 'assets/allacrost_enemy_sprites/arcana_drake.png');
    this.game.load.image('aurum-drakueli', 'assets/allacrost_enemy_sprites/aurum-drakueli.png');
    this.game.load.image('bat', 'assets/allacrost_enemy_sprites/bat.png');
    this.game.load.image('daemarbora', 'assets/allacrost_enemy_sprites/daemarbora.png');
    this.game.load.image('deceleon', 'assets/allacrost_enemy_sprites/deceleon.png');
    this.game.load.image('demonic_essence', 'assets/allacrost_enemy_sprites/demonic_essence.png');
    this.game.load.image('dune_crawler', 'assets/allacrost_enemy_sprites/dune_crawler.png');
    this.game.load.image('green_slime', 'assets/allacrost_enemy_sprites/green_slime.png');
    this.game.load.image('nagaruda', 'assets/allacrost_enemy_sprites/nagaruda.png');
    this.game.load.image('rat', 'assets/allacrost_enemy_sprites/rat.png');
    this.game.load.image('scorpion', 'assets/allacrost_enemy_sprites/scorpion.png');
    this.game.load.image('skeleton', 'assets/allacrost_enemy_sprites/skeleton.png');
    this.game.load.image('snake', 'assets/allacrost_enemy_sprites/snake.png');
    this.game.load.image('spider', 'assets/allacrost_enemy_sprites/spider.png');
    this.game.load.image('stygian_lizard', 'assets/allacrost_enemy_sprites/stygian_lizard.png');

In the create  method is where we’ll want to create Sprite objects for these images so that they can exist in the game world. Much like the background images, it’s faster and easier to read if we put all the information that we need to load into an array. This time however, we need more than just the image key. We’re going to want to display the name of the monster on the screen below it, so that the player knows what they are facing. To do this we’ll create an array of objects that has a name property suitable for display, as well as the image key.

var monsterData = [
    {name: 'Aerocephal', image: 'aerocephal'},
    {name: 'Arcana Drake', image: 'arcana_drake'},
    {name: 'Aurum Drakueli', image: 'aurum-drakueli'},
    {name: 'Bat', image: 'bat'},
    {name: 'Daemarbora', image: 'daemarbora'},
    {name: 'Deceleon', image: 'deceleon'},
    {name: 'Demonic Essence', image: 'demonic_essence'},
    {name: 'Dune Crawler', image: 'dune_crawler'},
    {name: 'Green Slime', image: 'green_slime'},
    {name: 'Nagaruda', image: 'nagaruda'},
    {name: 'Rat', image: 'rat'},
    {name: 'Scorpion', image: 'scorpion'},
    {name: 'Skeleton', image: 'skeleton'},
    {name: 'Snake', image: 'snake'},
    {name: 'Spider', image: 'spider'},
    {name: 'Stygian Lizard', image: 'stygian_lizard'}
];

After that, we’ll need to create the actual sprites for them in order to render them in the game world. Time for another group!

this.monsters = this.game.add.group();

var monster;
monsterData.forEach(function(data) {
    // create a sprite for them off screen
    monster = state.monsters.create(1000, state.game.world.centerY, data.image);
    // center anchor
    monster.anchor.setTo(0.5);
    // reference to the database
    monster.details = data;

    //enable input so we can click it!
    monster.inputEnabled = true;
    monster.events.onInputDown.add(state.onClickMonster, state);
});

When it comes to sprites, groups have a special method create that we can use. For other game objects we need to create them using the normal game factories, and add them as children to the group, the create method only works for sprites. It takes the normal sprite parameters; position and image key, but also lets you pass in a flag as to whether or not the sprite “exists”. This parameter is most often used in object pooling, which we’ll cover a bit later. Each sprite we’ll set the anchor to the center, and set a reference to our monsterData item so that we can reference it later (to display the name).

We’re also going to want to be able to click the monsters (it’s a *click*er game after all), we can tell Phaser to register click events by setting inputEnabled to true. Doing so will enable several input events, we’re interested in what happens when we click the mouse button down (or tap it). For that we’ll tell it to use the onClickMonster  method of our state, and that it should be called in the context of our state (javascript “this”). We haven’t created that method yet, we’ll do that in a minute.

In this game, we only ever want to face one monster at a time, so we need a reference to the monster that we are currently facing. Another cool feature of a group is that we can let Phaser randomly select one using getRandom() . Then set the position of the monster to roughly the center of the screen, a little off so that we have room for some other things later.

this.currentMonster = this.monsters.getRandom();
this.currentMonster.position.set(this.game.world.centerX + 100, this.game.world.centerY);

Next we can modify our render method so that we can show the name of the monster that we are up against.

render: function() {
    game.debug.text(this.currentMonster.details.name,
        this.game.world.centerX - this.currentMonster.width / 2,
        this.game.world.centerY + this.currentMonster.height / 2);
}

Finally, we need to add that onClickMonster  handler so that something happens when we click them. For now, we’ll just change out the monster on each click so that we can test running through our list (epic insta-kill!). Each click we’ll set the currentMonster to another random one, and position it in the center of the screen. We’ll move the other monster off screen so that we can’t see it at the same time.

onClickMonster: function() {
    // reset the currentMonster before we move him
    this.currentMonster.position.set(1000, this.game.world.centerY);
    // now pick the next in the list, and bring him up
    this.currentMonster = this.monsters.getRandom();
    this.currentMonster.position.set(this.game.world.centerX + 100, this.game.world.centerY);
},

Reminder: time to commit your files again!

Phaser 3 game with tentacle dragon enemy in scene

Clicking For Great Justice

Obviously just clicking to cycle through the monsters isn’t much of a gameplay element. Instead we need to simulate RPG combat by clicking and dealing damage to the monsters. In order to deal damage, we need to know something about our player. The main hero of this game isn’t directly represented by a sprite on the screen, so we will just create a plain javascript object to hold useful information about them. Add this to the bottom of the create phase:

// the main player
this.player = {
    clickDmg: 1,
    gold: 0
};

Also in order to be able to kill the monsters, they need to have some health to damage. Let’s go back to our monster database from before, and add a maxHealth attribute to each one. For now, for the values of maxHealth, I’ve just chosen somewhat arbitrary numbers, by looking at the sprite and just making a few tougher than the others. Later we can get deeper into gameplay and balance out the toughness of the monsters. I also adjusted the spacing so that it looks a little more like a table and is easier to edit.

var monsterData = [
    {name: 'Aerocephal',        image: 'aerocephal',        maxHealth: 10},
    {name: 'Arcana Drake',      image: 'arcana_drake',      maxHealth: 20},
    {name: 'Aurum Drakueli',    image: 'aurum-drakueli',    maxHealth: 30},
    {name: 'Bat',               image: 'bat',               maxHealth: 5},
    {name: 'Daemarbora',        image: 'daemarbora',        maxHealth: 10},
    {name: 'Deceleon',          image: 'deceleon',          maxHealth: 10},
    {name: 'Demonic Essence',   image: 'demonic_essence',   maxHealth: 15},
    {name: 'Dune Crawler',      image: 'dune_crawler',      maxHealth: 8},
    {name: 'Green Slime',       image: 'green_slime',       maxHealth: 3},
    {name: 'Nagaruda',          image: 'nagaruda',          maxHealth: 13},
    {name: 'Rat',               image: 'rat',               maxHealth: 2},
    {name: 'Scorpion',          image: 'scorpion',          maxHealth: 2},
    {name: 'Skeleton',          image: 'skeleton',          maxHealth: 6},
    {name: 'Snake',             image: 'snake',             maxHealth: 4},
    {name: 'Spider',            image: 'spider',            maxHealth: 4},
    {name: 'Stygian Lizard',    image: 'stygian_lizard',    maxHealth: 20}
];

Phaser sprites come with both Health and LifeSpan components built in that provide all of the features that we need in order to get combat working. They provide us with a damage()  and heal()  method and take into account health and maxHealth in those methods. When you apply damage and the health drops to 0 (or below) it will automatically call kill()  and fire the onKilled  event. Similarly, there is a  revive()  method that allows you to bring a monster back from the dead fully healed. When a monster is revived, it fires the onRevived event. We will hook into those events to drop loot and change monsters. Inside the loop that creates the monster sprites, let’s set the health component based on the value in our data array.

// use the built in health component
monster.health = monster.maxHealth = data.maxHealth;

// hook into health and lifecycle events
monster.events.onKilled.add(state.onKilledMonster, state);
monster.events.onRevived.add(state.onRevivedMonster, state);

Next update the onClickMonster  method to deal damage to the monster based on the player’s clickDmg  attribute. When the monster’s health reaches 0, it will be killed.

onClickMonster: function(monster, pointer) {
    // apply click damage to monster
    this.currentMonster.damage(this.player.clickDmg);
}

Clicking on a monster will do damage, but it’s important to provide feedback to the player that this is happening. No one likes to click things and see nothing happen, it feels broken. Also, I think it’s time to get rid of the debug text and use an actual text object to display the monster’s name and health. Add these 2 Text objects to your create method. Again we’ll create another group so that moving the monster information around is easy. Creating Text objects is relatively straight forward, like most display objects you provide it the position on the screen (or relative to its parent), but instead of an image key, you pass it the string that you want to display. Optionally you can send in font styling data to change how it’s displayed. This font style information is very similar to standard HTML Canvas fonts.

this.monsterInfoUI = this.game.add.group();
this.monsterInfoUI.position.setTo(this.currentMonster.x - 220, this.currentMonster.y + 120);
this.monsterNameText = this.monsterInfoUI.addChild(this.game.add.text(0, 0, this.currentMonster.details.name, {
    font: '48px Arial Black',
    fill: '#fff',
    strokeThickness: 4
}));
this.monsterHealthText = this.monsterInfoUI.addChild(this.game.add.text(0, 80, this.currentMonster.health + ' HP', {
    font: '32px Arial Black',
    fill: '#ff0000',
    strokeThickness: 4
}));

Back in our onClickMonster  event, we want to update the text now to reflect the monster’s new health.

// update the health text
this.monsterHealthText.text = this.currentMonster.alive ? this.currentMonster.health + ' HP' : 'DEAD';

When a monster is killed it fires the onKilled  event, we want to push it back off screen and then select a new monster and revive them. The revive method optionally takes a health parameter that will set the health of the monster to the value provided. It then sets alive, visible, and exists to true, and then fires the onRevived event. Add the onKilledMonster  method to our state now.

onKilledMonster: function(monster) {
    // move the monster off screen again
    monster.position.set(1000, this.game.world.centerY);

    // pick a new monster
    this.currentMonster = this.monsters.getRandom();
    // make sure they are fully healed
    this.currentMonster.revive(this.currentMonster.maxHealth);
},

When a monster is revived, we want to get them into position on the screen, and reset the monster display text to reflect the new monster. After the kill handler, let’s add the onRevivedMonster  event handler to our state as well. Here we move the monster to the center area of the screen and update our text objects to reflect the new information.

onRevivedMonster: function(monster) {
    monster.position.set(this.game.world.centerX + 100, this.game.world.centerY);
    // update the text display
    this.monsterNameText.text = monster.details.name;
    this.monsterHealthText.text = monster.health + 'HP';
},

Ok, now we can see what is happening, and that is good. It still doesn’t quite feel exciting enough though, I think we can add more. For every click, let’s display the damage that we’re doing. For that, we’ll want to create a pool of text objects. Each click we need to display the damage number for a short period and then it should disappear. Instead of creating a new text object for each click (which we could do), it’s better to create a bunch up front and just change the properties. The reason is that in almost all programming situations, especially in JavaScript, creating new objects is an expensive operation. Not something that you want to be doing a lot of every frame. Let’s create a pool of about 50 text objects (I think I can do 30 clicks / second so that’s a decent buffer). The following should go in your create  method.

this.dmgTextPool = this.add.group();
var dmgText;
for (var d=0; d<50; d++) {
    dmgText = this.add.text(0, 0, '1', {
        font: '64px Arial Black',
        fill: '#fff',
        strokeThickness: 4
    });
    // start out not existing, so we don't draw it yet
    dmgText.exists = false;
    dmgText.tween = game.add.tween(dmgText)
        .to({
            alpha: 0,
            y: 100,
            x: this.game.rnd.integerInRange(100, 700)
        }, 1000, Phaser.Easing.Cubic.Out);

    dmgText.tween.onComplete.add(function(text, tween) {
        text.kill();
    });
    this.dmgTextPool.add(dmgText);
}

As you can see in order to create a pool of damage text objects to use we didn’t have to do anything special. We used the groups that we already know and love. A standard for loop will help us create 50 of them, and we’ll set them all to exists = false  so that they don’t render on the screen until we tell them to. Next, we’re going to add another super powerful tool in Phaser’s arsenal, a Tween. A tween allows you to modify various properties of an object over time. It uses one of several mathematical equations to “ease” these values from start to finish and create animation effects. For the damage text, we want it to fly out from where it was clicked in a random direction and also fade out so that by the time that it reaches its destination, it can no longer be seen. In the to  method of the tween, we set the final values that we want the alpha, y and x properties of the object to be, the starting values will be the values of the object when the tween begins. The second parameter is the time that it should take to complete the tween, we’ll set it to 1000 (the value is in milliseconds, so 1 second). The final parameter is the Easing equation that we want to use. When a tween animation is completed, an event is fired, we can hook into there and kill()  the text object (effectively setting it back to exists = false ).

Now we’ll turn these on so that clicking to do damage is really exciting. Every time we click, we’ll grab the first available dmgText object (i.e. not killed) from the group using getFirstExists(false) , the false tells the group that we want one that doesn’t exist. Then update the text to reflect the current click damage. We need to reset the alpha property from when the tween had adjusted it, and we want to start this one at the spot where the player clicked. Then we’ll start the tween again, and get our animation.

// grab a damage text from the pool to display what happened
var dmgText = this.dmgTextPool.getFirstExists(false);
if (dmgText) {
    dmgText.text = this.player.clickDmg;
    dmgText.reset(pointer.positionDown.x, pointer.positionDown.y);
    dmgText.alpha = 1;
    dmgText.tween.start();
}

Reminder: commit that code!

Demonic Essence enemy with damage displayed from attack

Phat Lootz

Killing monsters isn’t something that the player does just for sport, they’re in it for the rewards of gold and treasure. We need to drop some loot when the monster dies, let’s add a gold coin to our images loading in the preload method.

this.game.load.image('gold_coin', 'assets/496_RPG_icons/I_GoldCoin.png');

To start with, every monster will drop a single gold coin when it dies. The player will need to click on them to collect them, and so there could be quite a few laying around before they decide to do that. To create a pool of gold coins, again we’ll utilize the group. This time, since we’re creating a pool of sprites, we can use a special method called createMultiple. This method is very similar to the create  method in that it only creates sprites, for this one, it takes a new parameter, the number that you want to create. Since we’re not using a for loop this time to create them, we need a way to setup some defaults without having to loop through our newly created group, for that, we have another method called setAll. It takes the property and value and applies that to each object in the group. We also want to register the onInputDown handler, since adding a handler to an event is a method, we use callAll to execute the events.onInputDown.add  method on each child of the group.

// create a pool of gold coins
this.coins = this.add.group();
this.coins.createMultiple(50, 'gold_coin', '', false);
this.coins.setAll('inputEnabled', true);
this.coins.setAll('goldValue', 1);
this.coins.callAll('events.onInputDown.add', 'events.onInputDown', this.onClickCoin, this);

Again we need feedback in the UI so that we know that we are collecting gold. Add this text object to the create  method.

this.playerGoldText = this.add.text(30, 30, 'Gold: ' + this.player.gold, {
    font: '24px Arial Black',
    fill: '#fff',
    strokeThickness: 4
});

Now we can add our click handler for the coins. When a coin is clicked, the goldValue  of the coin is added to the player’s gold. We also have to update the UI so that we can see the change. Finally, we kill the coin so that it disappears back into our pool for reuse.

onClickCoin: function(coin) {
    // give the player gold
    this.player.gold += coin.goldValue;
    // update UI
    this.playerGoldText.text = 'Gold: ' + this.player.gold;
    // remove the coin
    coin.kill();
}

Next we need to add to the onKilledMonster  event so that we can actually drop these coins. Much like the dmgText objects, we’ll grab the first available coin and bring it to life positioning it somewhere randomly in the center-ish of the screen. We update the goldValue (even though we’re just setting it to 1 now) so that in the future we can drop different amounts of gold as we progress.

var coin;
// spawn a coin on the ground
coin = this.coins.getFirstExists(false);
coin.reset(this.game.world.centerX + this.game.rnd.integerInRange(-100, 100), this.game.world.centerY);
coin.goldValue = 1;

Dune Crawler enemy with Gold amount displayed in the upper left corner

As I mentioned earlier, the player has to click on the coins in order to collect them. After a few kills, if they don’t do that, the floor will become quite littered with gold. While piles of cash is always fun, eventually we might run out of new coins to spawn from our pool. What we need to do is automatically collect gold for the player after a short time so that the world doesn’t become cluttered.

To accomplish this, Phaser has a Timer object that we can use to create our own custom timed events. If the coin sits there not being clicked for 3 seconds, then we’ll “click” it for them, by firing the same onClickCoin  method that we use when they do click it. The timer event takes the duration, the handler, the context that the handler should fire in, and any other additional parameters that should be passed to the handler.

this.game.time.events.add(Phaser.Timer.SECOND * 3, this.onClickCoin, this, coin);

Since we are going to be calling the onClickCoin  method when the timer completes in addition to when the coin is clicked, we need to test and make sure that we don’t call it twice. If the player clicks the coin before the timeout, the timeout will still fire, but the gold will already be collected, and the coin already killed. We can add a simple test at the top of the function to make sure that when we collect this coin it is still alive.

if (!coin.alive) {
    return;
}

Reminder: commit the source, save your work!

Upgrades

I’m sure by now you’re tired of doing just 1 point of damage every click, and we’ve got nothing to spend our precious gold on! Time to create some upgrades. The upgrades menu is going to be a box, with some buttons inside that you can click on to buy things. For the background of the upgrades menu, we could use more art from the web, or create an image ourselves in a paint program, but instead we can utilize the HTML5 Canvas to build it for us. Instead of loading an image, Phaser has an object called BitmapData that creates a canvas for us. The result of the canvas can then be used in place of an image on a sprite. Instead of setting the key when it is loaded like with an image, instead we need to manually add it to Phaser’s asset cache. In the preload  method we will generate images (colored rectangles) for the background of the upgrades menu and also the buttons.

// build panel for upgrades
var bmd = this.game.add.bitmapData(250, 500);
bmd.ctx.fillStyle = '#9a783d';
bmd.ctx.strokeStyle = '#35371c';
bmd.ctx.lineWidth = 12;
bmd.ctx.fillRect(0, 0, 250, 500);
bmd.ctx.strokeRect(0, 0, 250, 500);
this.game.cache.addBitmapData('upgradePanel', bmd);

var buttonImage = this.game.add.bitmapData(476, 48);
buttonImage.ctx.fillStyle = '#e6dec7';
buttonImage.ctx.strokeStyle = '#35371c';
buttonImage.ctx.lineWidth = 4;
buttonImage.ctx.fillRect(0, 0, 225, 48);
buttonImage.ctx.strokeRect(0, 0, 225, 48);
this.game.cache.addBitmapData('button', buttonImage);

For the upgrades menu, we don’t need something as heavy as a sprite (with all the health and other stuff). Instead for things that are going to be purely user interface objects, it is better to use a Image. An Image object has the same transform information (position, scale, rotation) just not all the extra things that a sprite does. Instead of passing in an image key, we’ll pull the image out of the cache that we put it into earlier. The menu panel will also contain a group for the buttons, that way all of the buttons can follow the menu and be relative to its transforms. Because of the border on the background image, we’ll move the button group in a little bit.

this.upgradePanel = this.game.add.image(10, 70, this.game.cache.getBitmapData('upgradePanel'));
var upgradeButtons = this.upgradePanel.addChild(this.game.add.group());
upgradeButtons.position.setTo(8, 8);

Stygian Lizard enemy with newly added upgrade frame

Our first upgrade will be to the click damage so we can start killing faster. Let’s pick an icon from our library and add that to our image load.

this.game.load.image('dagger', 'assets/496_RPG_icons/W_Dagger002.png');

Phaser has another object in its bag of tricks, the Button object. A button is a subclass of an Image object that is designed to handle being clicked out of the box. It supports 4 different button states: Out, Over, Down, and Up. You can provide a spritesheet image with different looks for each of these states, it can make the button appear to actually be “pressed” for example, or change color when you hover over top of it. I’ve only generated a single background frame for our buttons for now, it still works fine without the other images. For the button we are going to add the icon, a label for what the upgrade is, and another text to display the gold cost for upgrading.

var button;
button = this.game.add.button(0, 0, this.game.cache.getBitmapData('button'));
button.icon = button.addChild(this.game.add.image(6, 6, 'dagger'));
button.text = button.addChild(this.game.add.text(42, 6, 'Attack: ' + this.player.clickDmg, {font: '16px Arial Black'}));
button.details = {cost: 5};
button.costText = button.addChild(this.game.add.text(42, 24, 'Cost: ' + button.details.cost, {font: '16px Arial Black'}));
button.events.onInputDown.add(this.onUpgradeButtonClick, this);

After creating the button, then add it to the buttons group.

upgradeButtons.addChild(button);

For now our button handler simply needs to test the one button that we have. First we’ll check that we can afford to purchase the upgrade, if we can then we’ll go through with it. We need to adjust the player’s gold from the cost, and update the UI to reflect that change. We also need to improve the player’s clickDmg attribute, and update the text on the button. Now we can spend our hard earned loot to get stronger!

onUpgradeButtonClick: function(button, pointer) {
    if (this.player.gold - button.details.cost >= 0) {
        this.player.gold -= button.details.cost;
        this.playerGoldText.text = 'Gold: ' + this.player.gold;
        this.player.clickDmg++;
        button.text.text = 'Attack: ' + this.player.clickDmg;
    }
}

Aerocephal enemy with Attack 21 as an upgrade

Now it’s time to add the second type of upgrade, the DPS upgrade. Until now the only way to deal damage to monsters is by directly clicking on them. While this is an important mechanic in our game, it can get tedious after a while. This is the part that makes this type of game fall into the “idle” genre. Players will continue to progress and deal damage to monsters even when they are not actively clicking them.

In order to add a new button, we need to repeat what we have, and change the effect of purchasing the upgrade. Doing this one button at a time will get unruly after a bit, so we want to create a database array of upgrades, just like we have for monsters. We’ll need the icon to display, the name of the upgrade, the level for the number of times that it has been upgraded, the cost in gold to upgrade, and a callback function that we can fire to provide a different effect for each upgrade.

var upgradeButtonsData = [
    {icon: 'dagger', name: 'Attack', level: 1, cost: 5, purchaseHandler: function(button, player) {
        player.clickDmg += 1;
    }},
    {icon: 'swordIcon1', name: 'Auto-Attack', level: 0, cost: 25, purchaseHandler: function(button, player) {
        player.dps += 5;
    }}
];

We need to add the dps property to our player, so that our purchase handler can take effect.

this.player = {
    clickDmg: 1,
    gold: 0,
    dps: 0
};

Now we can loop through our data and create all of our upgrade buttons in bulk. Because the buttons are about 48 pixels high, we’ll separate each one by 50. Instead of hard coding the text strings and icon, they will be populated from the data.

var button;
upgradeButtonsData.forEach(function(buttonData, index) {
    button = state.game.add.button(0, (50 * index), state.game.cache.getBitmapData('button'));
    button.icon = button.addChild(state.game.add.image(6, 6, buttonData.icon));
    button.text = button.addChild(state.game.add.text(42, 6, buttonData.name + ': ' + buttonData.level, {font: '16px Arial Black'}));
    button.details = buttonData;
    button.costText = button.addChild(state.game.add.text(42, 24, 'Cost: ' + buttonData.cost, {font: '16px Arial Black'}));
    button.events.onInputDown.add(state.onUpgradeButtonClick, state);

    upgradeButtons.addChild(button);
});

When we click an upgrade button now we need to increase its level and update the text to reflect the change. Then we’ll execute the purchaseHandler callback in the context of the state, passing the button and player along to the handler.

onUpgradeButtonClick: function(button, pointer) {
    if (this.player.gold - button.details.cost >= 0) {
        this.player.gold -= button.details.cost;
        this.playerGoldText.text = 'Gold: ' + this.player.gold;
        button.details.level++;
        button.text.text = button.details.name + ': ' + button.details.level;
        button.details.purchaseHandler.call(this, button, this.player);
    }
}

Ok, so we’re increasing both attack and dps (damage per second), but we haven’t setup dps to do anything yet. For dps to make sense, if we have 1 dps then after 1 second has passed we do 1 damage. Waiting the full second to apply any damage at all though is too choppy and slow. Instead we’ll update at 100ms (10 times a second). So, in order to apply 1 damage after 1 second, then we need to apply 0.10 damage every 100ms. Similar to the timer event that we used for the gold coins, there are also loop events that will repeat and call the handler at the duration over and over.

// 100ms 10x a second
this.dpsTimer = this.game.time.events.loop(100, this.onDPS, this);

Our dps handler is going to get called every 100ms whether we have upgraded or not. So we check if we have something to do first, if so, then make sure the monster is still alive to apply the damage. Then we’ll damage the monster and update the text to reflect the monster’s health. I don’t really want to display the decimals that might occur on the monster health from doing 10% damage, so we’ll round it for the display (not the actual health).

onDPS: function() {
    if (this.player.dps > 0) {
        if (this.currentMonster && this.currentMonster.alive) {
            var dmg = this.player.dps / 10;
            this.currentMonster.damage(dmg);
            // update the health text
            this.monsterHealthText.text = this.currentMonster.alive ? Math.round(this.currentMonster.health) + ' HP' : 'DEAD';
        }
    }
}

Reminder: don’t forget to commit!

Progression

Killing the same monsters over and over is boring. We need to keep increasing the difficulty so that the players can face a challenge and progress. Let’s add some world level stats to the preload  section.

// world progression
this.level = 1;
// how many monsters have we killed during this level
this.levelKills = 0;
// how many monsters are required to advance a level
this.levelKillsRequired = 10;

Each time we kill a monster now, we need to increase the kills stat. We also need to upgrade the monster’s health based on the level. With increased risk, comes increased reward, and we’ll also modify the coin value based on the world level as well. After 10 monsters have been killed, then we can progress to the next level.

onKilledMonster: function(monster) {
    // move the monster off screen again
    monster.position.set(1000, this.game.world.centerY);

    var coin;
    // spawn a coin on the ground
    coin = this.coins.getFirstExists(false);
    coin.reset(this.game.world.centerX + this.game.rnd.integerInRange(-100, 100), this.game.world.centerY);
    coin.goldValue = Math.round(this.level * 1.33);
    this.game.time.events.add(Phaser.Timer.SECOND * 3, this.onClickCoin, this, coin);

    this.levelKills++;

    if (this.levelKills >= this.levelKillsRequired) {
        this.level++;
        this.levelKills = 0;
    }

    // pick a new monster
    this.currentMonster = this.monsters.getRandom();
    // upgrade the monster based on level
    this.currentMonster.maxHealth = Math.ceil(this.currentMonster.details.maxHealth + ((this.level - 1) * 10.6));
    // make sure they are fully healed
    this.currentMonster.revive(this.currentMonster.maxHealth);
}

Since we’ll be getting a lot more money now, we also need to adjust the upgrade prices.

onUpgradeButtonClick: function(button, pointer) {
    // make this a function so that it updates after we buy
    function getAdjustedCost() {
        return Math.ceil(button.details.cost + (button.details.level * 1.46));
    }

    if (this.player.gold - getAdjustedCost() >= 0) {
        this.player.gold -= getAdjustedCost();
        this.playerGoldText.text = 'Gold: ' + this.player.gold;
        button.details.level++;
        button.text.text = button.details.name + ': ' + button.details.level;
        button.costText.text = 'Cost: ' + getAdjustedCost();
        button.details.purchaseHandler.call(this, button, this.player);
    }
}

Finally, we’ll add the level information to the UI so that the player knows how they are doing. By now adding text objects to reflect this information should be old hat to you!

// setup the world progression display
this.levelUI = this.game.add.group();
this.levelUI.position.setTo(this.game.world.centerX, 30);
this.levelText = this.levelUI.addChild(this.game.add.text(0, 0, 'Level: ' + this.level, {
    font: '24px Arial Black',
    fill: '#fff',
    strokeThickness: 4
}));
this.levelKillsText = this.levelUI.addChild(this.game.add.text(0, 30, 'Kills: ' + this.levelKills + '/' + this.levelKillsRequired, {
    font: '24px Arial Black',
    fill: '#fff',
    strokeThickness: 4
}));

We also need to update the level text when it changes inside the  onKilledMonster  method.

this.levelText.text = 'Level: ' + this.level;
this.levelKillsText.text = 'Kills: ' + this.levelKills + '/' + this.levelKillsRequired;

Spider enemy with various upgrades in Phaser 3 game

Reminder: commit commit commit

Finished the basics, what’s next?

What we’ve created here is a complete idle clicker RPG. Well, complete as in it’s playable. There’s still tons left to do in order to get this game turned into something that is really fun. In game development, they say that the last 10% of the work is the last 90% of your time. We’re pretty much 90% done I think 🙂

Here’s a list of things that would be great to add: (possibly in future tutorials)

  • monsters with animation
  • sounds & music!
  • more upgrades
  • critical hits
  • boss monsters
  • timed boost powers
  • different world backgrounds
  • achievements
  • leader boards

I hope that you have enjoyed this tutorial and making this game!

Please leave comments and questions below, I welcome any feedback and would love to see your games too!

]]>
How to Make an HTML5 Game https://gamedevacademy.org/how-to-make-a-html5-game/ Thu, 06 Jan 2022 09:30:39 +0000 https://gamedevacademy.org/?p=1585 Read more]]> Although Flash games have departed from this world, there is still a significant demand for browser-based and cross-platform games. Whether you yourself actively play them or not, more and more games from professional and indie developers alike come out each day.

This phenomenon is largely thanks to HTML5 games which have filled the gap to keep up with these eager gamers. In addition, thanks to the advancement of technology and new frameworks, HTML5 game development has reached extensive heights, allowing for multiplayer experiences, 3D graphics, and more! It is not unwise to say that gaming is now just as viable via a browser as it is on many other devices!

Assuming this sounds like an exciting prospect to you as a game developer, in this guide we’re going to delve into the topic of HTML5 game development and give you the run-down of how you can make your own games! Sit back, relax, and prepare to enhance your game development skills in entirely new ways!

What exactly is an HTML5 game?

Let’s start from total zero. What is HTML5? that’s a tricky question. There is an official definition of HTML5, which simply stands for the latest revision of HTML (the markup language used all over the world to build websites), and the more hyped definition (what most people understand when HTML5 is mentioned) which is all the “new” features of the web technologies that have come out in the last few years (JavaScript API’s like the Canvas or WebAudio, semantic HTML tags, etc).

For our purpose, we’ll use bits of the two. HTML5 is HTML in its latest version, which includes a whole bunch of cool features that make web technologies an open standard with endless possibilities combining HTML, CSS and JavaScript.

Having HTML along with all these superpowers that go beyond making a simple website allows us to make, among other things, games. These are HTML5 games.

BUILD YOUR OWN GAMES

Get 250+ coding courses for

$1

AVAILABLE FOR A LIMITED TIME ONLY

 Building blocks

The very basic building blocks of a HTML5 game are those of the web:

  • HTML
  • CSS
  • JavaScript

Similarly to what happens with HTML5, when people talk about CSS3 they usually refer to the new things that come with CSS’s latest specifications, but in an analog manner, CSS3 is simply the latest CSS. Ignoring for a second the semantics of these definitions and thinking of the hyped versions of these terms, we also may need, in order to make HTML5 games:

  • HTML5 (JavaScript API’s)
  • CSS3

With the above you can make awesome games that will run on modern web browsers on mobile and desktop, but some games might require more features, so there are more building blocks that you can add.

For instance, you may want to make 3D games. If that is the case there is also WebGL, which is a JavaScript API to render 2D and 3D graphics on the browser, using the GPU for greater performance.

Road crossing game made with HTML5

Server side

If you want your games to saved data remotely you’ll need a server-side for your game. You can develop your own backend using any server-side language, you’ll need well a server in this case.

  • JavaScript (NodeJS)
  • PHP
  • Java
  • Python
  • Ruby

Or you can use a third-party Backend-as-a-Service provider such as Firebase or Parse. Some have free versions you can use and they’ll start charging you once you surpass certain limits. Some of these providers are particularly focused on games, some are mostly conceived for mobile apps but can be used for games too.

How to distribute a HTML5 game

The easiest way to distribute a HTML5 is to simply put it out there! By being built as a website, you can just embed it in on a page and publish it. Just like that.

If you want to distribute it through proprietary platforms you have to go through a process called wrapping. Basically, you create a native app for the platform you wanna distribute it to (iOS, Android, etc) and put your game inside so that this app acts like a web browser and “runs” your game.

For desktop platforms such as Windows, Mac or Linux there is a tool called NWjs that allows you to pack your HTML5 games for these platforms.

We can only cover the basics here, but we encourage you to read our more in-depth advice about publishing games.

Match 3 game made with HTML5

HTML5 game frameworks

Most games share some concepts, that of sprites (graphic elements that represent enemies, players, elements in your game), scenes or stages, animations, sound, loading graphic assets, etc. Since most game developers want to focus on their actual game and not in creating this whole abstraction layer, it is recommended you use a HTML5 game frameworks.

HTML5 game frameworks and libraries that contain building components you can use to create your own games. These libraries are Open Source projects created and maintained by people who want to contribute to the HTML5 gamedev environment. In many cases they created the frameworks for their own games, and after realizing that other people would want to not only use it but also contribute to it they released them as Open Source code, so everybody wins.

Picking what game engine to use is an important decision, so make sure you do proper research before making your choice. No matter what engine you pick, you will have to get familiar with its code and inner working if you want to use properly, so they shouldn’t be treated as black boxes.

What can help you make your choice:

  • Is your game for desktop, mobile or both?
  • Do they have an active community?
  • Are there many people using the framework nowadays?
  • Is it being maintained or the Github page looks like an abandoned town?

Sometimes looking at real games gives you more insight than just words. This project compares different engines by making the exact same Breakout game in all of them.

Some popular free frameworks are:

Solar system project made with Babylon.js

HTML5 game development courses

Video courses are a great way to learn new technologies. The main difference between a video course and just watching YouTube videos is that there is more structure. Good courses have a clear goal and build on to it step by step. Below a list of courses and tutorials by Zenva that can give you the tools you need to create HTML5 games.

General Game Development

Phaser

WebGL, 3D, and XR

HTML5 Skills

At the GameDev Academy, as you know already we have a bunch of HTML5 game development tutorials, mostly on Phaser, LimeJs, Quintus and BabylonJS. There are other great places to find good quality HTML5 gamedev tuts:

HTML5 for Schools

Are you a teacher looking to help students get into frameworks like Phaser or teach them core and relevant web development skills? Try out Zenva Schools – an online platform offering coding-based courses for use in the classroom. The platform comes with video lessons, text summaries, quizzes, classroom management features, reporting, and more to help support learning HTML5!

HTML5 gamedev communities

You can find plenty of active communities on the Internet, some focus on gamedev in general and some others just in HTML5 gamedev.

Web:

Facebook:

Other Communities:

HTML5 gamedev challenges

  • The Global Game Jam® is an annual event, usually occurring in January every year. Participants work concurrently around the globe, and around a central theme, and then work together to create a game.
  • j13k competition: the competition is over but you can still read the Blog, subscribe to the Newsletter, and check the Resources for tools.

 HTML5 gamedev podcasts

I just know Lostcast, a podcast created by the guys from Lost Decade Games (whom we’ve interviewed in the past). In the podcast episodes they talk about they HTML5 games and game development in general.

BUILD GAMES

FINAL DAYS: Unlock 250+ coding courses, guided learning paths, help from expert mentors, and more.

]]>
RPG Game Development with Phaser https://gamedevacademy.org/rpg-game-development-with-phaser/ Mon, 06 Feb 2017 02:24:36 +0000 https://gamedevacademy.org/?p=4620 Read more]]> Ever wanted to create games with vast worlds to explore and dungeons filled with monsters and treasure? Do you have intermediate Javascript skills? Then you are ready to become an RPG game developer.

Using Javascript and Phaser, you will create world maps and dungeons using open source tools, turn-based battles with magic attacks, learn about player level ups and UI screens, create classic RPG towns with non-player characters and save your game progress in the cloud with Firebase. The world of RPG games are waiting for you.

Access this course on Zenva Academy

]]>
How to Create a Pokemon GO Game – Part 4 https://gamedevacademy.org/how-to-create-a-pokemon-go-game-part-4/ Wed, 30 Nov 2016 07:37:19 +0000 https://gamedevacademy.org/?p=4429 Read more]]> In the previous tutorial we finished adding the gameplay content to our game. Now, in this last part of the Pokemon GO tutorial series, we are going to add Google and Facebook authentication, to allow saving the game data on an online database. We are going to use Firebase as the framework for authentication and online storage. The following topics will be covered in this tutorial:

  • Creating a Firebase app
  • Adding Google authentication
  • Creating an app as Facebook developer
  • Adding Facebook authentication
  • Adding online storage

To read this tutorial, it is important that you are familiar with the following concepts:

  • Javascript and object-oriented concepts.
  • Basic Phaser concepts, such as: states, sprites, groups and arcade physics
  • Creating maps using Tiled

 Become a Game Developer by building 15 games

If you want to master Phaser and learn how to publish Phaser games as native games for iOS and Android feel free to check Zenva‘s online course The Complete Mobile Game Development Course – Build 15 Games.

Source code files

You can download the tutorial source code files here.

 Creating Firebase app

Firebase is a Google framework that provides different functionalities for web and mobile apps, such as authentication, realtime database, analytics and cloud messaging. We are going to use it only for authentication and for the realtime database, but you can check their documentation for examples of other features.

The first thing we have to do is creating a Firebase account and a new Firebase app. In the image below I created a Firebase app called Phasermon GO. Then, by clicking on “Add Firebase to your web app” the console will show how to add Firebase to your app code.

add_firebase

For this tutorial, we are going to add the script tag in the index.html file, while the “config” variable and initialization will be added to main.js. For now, you can try running your game and checking if there is no Firebase error.

var Pokemon = Pokemon || {};

var config = {
    apiKey: "AIzaSyAx4NNN2oIYxHWS8H4Uhom4EgN0VpugWlc",
    authDomain: "phasermon-go.firebaseapp.com",
    databaseURL: "https://phasermon-go.firebaseio.com",
    storageBucket: "phasermon-go.appspot.com",
    messagingSenderId: "375905605428"
};
firebase.initializeApp(config);

var game = new Phaser.Game(320, 640, Phaser.CANVAS);

game.caught_pokemon = this.game.caught_pokemon || [];
game.number_of_pokeballs = this.game.number_of_pokeballs || {pokeball: 0, greatball: 1, ultraball: 2};

game.state.add("BootState", new Pokemon.BootState());
game.state.add("LoadingState", new Pokemon.LoadingState());
game.state.add("TitleState", new Pokemon.TitleState());
game.state.add("WorldState", new Pokemon.WorldState());
game.state.add("CatchState", new Pokemon.CatchState());
game.state.start("BootState", true, false, "assets/levels/title_screen.json", "TitleState");

Disclaimer: for some reason Firebase is not working for Google Chrome in my computer. So, if you experience issues with it, trying running it on Firefox to see if it is a browser related issue.

Adding Google authentication

Now, we are going to add Google authentication to our game. First, we must enable it in the Firebase console, by going to the Authentication section in the menu, and then the Sign-in Method tab. Then, we enable Google authentication. We also need to add “127.0.0.1” as an OAuth redirect domain in order to test our game.

google_authNow we are going to change our TitleState to allow authentication. For now we are going to simply change the input event to start the login procedure. Later, when we add Facebook authentication, we will create buttons for the different login types.

var Pokemon = Pokemon || {};

Pokemon.TitleState = function () {
    "use strict";
    Pokemon.JSONLevelState.call(this);
    
    this.prefab_classes = {
        "text": Pokemon.TextPrefab.prototype.constructor,
        "login_button": Pokemon.LoginButton.prototype.constructor
    };
};

Pokemon.TitleState.prototype = Object.create(Pokemon.JSONLevelState.prototype);
Pokemon.TitleState.prototype.constructor = Pokemon.TitleState;

Pokemon.TitleState.prototype.create = function () {
    "use strict";
    var pokemon_data;
    Pokemon.JSONLevelState.prototype.create.call(this);
    
    this.game.input.onDown.add(this.login, this);
};

Pokemon.TitleState.prototype.login = function (provider) {
    "use strict";
    var provider, user;
    if (!firebase.auth().currentUser) {
        provider = new firebase.auth.GoogleAuthProvider();
        //provider.addScope('https://www.googleapis.com/auth/plus.login');
        provider.addScope("https://www.googleapis.com/auth/userinfo.email");
        
        firebase.auth().signInWithPopup(provider).then(this.start_game.bind(this)).catch(Pokemon.handle_error);
    } else {
        firebase.database().ref("/users/" + firebase.auth().currentUser.uid).once("value").then(this.start_game.bind(this));
    }
};

Pokemon.TitleState.prototype.start_game = function () {
    "use strict";
    this.game.state.start("BootState", true, false, "assets/levels/world_level.json", "WorldState");
};

The “login” method will start by checking if there is a current user authenticated with Firebase. If so, it will simply start the game. If not, it will create a new GoogleAuthProvider to perform the authentication. The next step is to add a scope, which will define the amount of data from the user account our app will have access. In this tutorial our app will only have access to the user email address (using the scope https://www.googleapis.com/auth/userinfo.email). Finally, we call the “signInWithPopup” method, which will open a popup window for the user to authenticate with its Google account. The “then” and “catch” methods add callbacks to when the operation concludes succesfully and when it fails, respectively.

When the user authenticates succesfully, the “start_game” method is called, which will simply start the game as before. On the other hand, if the authentication fails, we need to handle the error. In this tutorial we are only going to add a function in Utils.js to print the error message. In a real app, you can try identifying the error cause and dealing with it, when appropriate.

Pokemon.handle_error = function (error) {
    "use strict";
    console.log(error);
};

By now, you can already test Google authentication by trying to login with your Google account.

Adding Facebook authentication

Before storing the game content in the online database, we are going to add Facebook authentication as well. The first thing we have to do is creating a Facebook app in Facebook for developers. You will need a Facebook account, and you might have to add a phone number or credit card number in order to verify your account.

create_facebook_appThe next step is enabling Facebook authentication on Firebase. This is similar to how we did with Google authentication, but we need to add our App ID and App secret.

facebook_authThe last step is enabling your Facebook app to be authenticated by Firebase. To do that, first we need to copy the OAuth redirect URI shown in the authentication page (https://phasermon-go.firebaseapp.com/__/auth/handler). Then, back in the Facebook for developers console, we need to add a Facebook Login product (by clicking on Add Product). In the Facebook Login settings page we need to add the Firebase OAuth redirect URI as a valid one.

facebook_login_settingsNow that we have enabled Facebook authentication, we need to change our code to allow the player to choose to authenticate with Google or Facebook.

In order to do that, we are going to create a LoginButton Prefab. The only difference between the code to login with Google or Facebook is the authentication provider and the scope string. So, LoginButton will have as properties both the provider and the scope. In order to select the provider object correctly, it will have an object to map each login type to the provider Object. In the end of the constructor we add an input event to call the “login” method.

var Pokemon = Pokemon || {};

Pokemon.LoginButton = function (game_state, name, position, properties) {
    "use strict";
    Pokemon.Prefab.call(this, game_state, name, position, properties);
    
    this.auth_providers = {
        google: firebase.auth.GoogleAuthProvider.prototype.constructor,
        facebook: firebase.auth.FacebookAuthProvider.prototype.constructor
    };
    
    this.auth_provider = properties.auth_provider;
    this.provider_scope = properties.provider_scope;
    
    this.inputEnabled = true;
    this.events.onInputDown.add(this.login, this);
};

Pokemon.LoginButton.prototype = Object.create(Pokemon.Prefab.prototype);
Pokemon.LoginButton.prototype.constructor = Pokemon.LoginButton;

Pokemon.LoginButton.prototype.login = function () {
    "use strict";
    var provider, user;
    if (!firebase.auth().currentUser) {
        provider = new this.auth_providers[this.auth_provider]();
        provider.addScope(this.provider_scope);
        
        firebase.auth().signInWithPopup(provider).then(this.game_state.start_game.bind(this.game_state)).catch(Pokemon.handle_error);
    } else {
        firebase.database().ref("/users/" + firebase.auth().currentUser.uid).once("value").then(this.game_state.start_game.bind(this.game_state));
    }
};

The “login” method is almost the same as the previous one from game state, but now we are going to use the provider and scope from the Prefab properties. If the player authenticates successfully, it calls the “start_game” method from game state as before.

Now, in game state we need to remove the “login” method and leave only the “start_game” method. We also are going to remove the input event from the game, since now the authentication will be done through the login buttons.

var Pokemon = Pokemon || {};

Pokemon.TitleState = function () {
    "use strict";
    Pokemon.JSONLevelState.call(this);
    
    this.prefab_classes = {
        "text": Pokemon.TextPrefab.prototype.constructor,
        "login_button": Pokemon.LoginButton.prototype.constructor
    };
};

Pokemon.TitleState.prototype = Object.create(Pokemon.JSONLevelState.prototype);
Pokemon.TitleState.prototype.constructor = Pokemon.TitleState;

Pokemon.TitleState.prototype.start_game = function () {
    "use strict";
    this.game.state.start("BootState", true, false, "assets/levels/world_level.json", "WorldState");
};

Also, remember to add the login button objects in the JSON level file of TitleState, and the LoginButton prefab in the “prefab_classes” object of TitleState.

{
    "assets": {
        "google_login_button_image": {"type": "image", "source": "assets/images/google_login_button.png"},
        "facebook_login_button_image": {"type": "image", "source": "assets/images/facebook_login_button.png"}
    },
    "groups": [
        "hud"
    ],
    "prefabs": {
        "title": {
            "type": "text",
            "position": {"x": 0.5, "y": 0.5},
            "properties": {
                "anchor": {"x": 0.5, "y": 0.5},
                "group": "hud",
                "text": "Phasermon GO",
                "style": {"font": "32px Arial", "fill": "#FFF"}
            }
        },
        "login_with_google_button": {
            "type": "login_button",
            "position": {"x": 0.5, "y": 0.7},
            "properties": {
                "anchor": {"x": 0.5, "y": 0.5},
                "group": "hud",
                "texture": "google_login_button_image",
                "auth_provider": "google",
                "provider_scope": "https://www.googleapis.com/auth/plus.login"
            }
        },
        "login_with_facebook_button": {
            "type": "login_button",
            "position": {"x": 0.5, "y": 0.9},
            "properties": {
                "anchor": {"x": 0.5, "y": 0.5},
                "group": "hud",
                "texture": "facebook_login_button_image",
                "auth_provider": "facebook",
                "provider_scope": "user_birthday"
            }
        }
    }
}

By now you can try running your game and try authenticating with both Google and Facebook. However, if you use your Google email for Facebook, you can’t authenticate with both at the same time. In this case, you will need to go to the authentication settings in Firebase and remove the Google user in order to authenticate with Facebook.

auth_delete

Saving game data online

Until now we are saving in the game the number of pokeballs of the player and caught pokemon. However, when the game restarts we lose this information and need to reset it to a default value. So now we are going to save it using Firebase online storage features. Firebase saves data as JSON objects, so it is very easy to use and integrate it in our code.

In order to do that we are going to add code to TitleState and change LoginButton callback method. Now, when the player succesfully authenticates, our code is going to call an “on_login” method from TitleState. This method will retrieve the current player data before starting the game.

Pokemon.LoginButton.prototype.login = function () {
    "use strict";
    var provider, user;
    if (!firebase.auth().currentUser) {
        provider = new this.auth_providers[this.auth_provider]();
        provider.addScope(this.provider_scope);
        
        firebase.auth().signInWithPopup(provider).then(this.game_state.on_login.bind(this.game_state)).catch(Pokemon.handle_error);
    } else {
        firebase.database().ref("/users/" + firebase.auth().currentUser.uid).once("value").then(this.game_state.start_game.bind(this.game_state));
    }
};

We can navigate through Firebase data using the “ref” method and the “slash” symbol to access object properties. Our app will have a root object called “users”. This object will have a property (called child in Firebase) for each player. This child will have the data for that specific player. So, in the “on_login” method we navigate to the current user object and retrieve its data. Firebase asynchronously manipulates data, so we need to add a callback to an event. In this case we are going to use the “once” event with the “value” parameter, which calls the callback method only the first time this data changes in the database (you can learn more on Firebase documentation). We are going to use it to retrieve the initial data for this player in the database.

Pokemon.TitleState.prototype.on_login = function (result) {
    "use strict";
    firebase.database().ref("/users/" + result.user.uid).once("value").then(this.start_game.bind(this));
};

The callback for the database operation is “start_game”. We are also going to change this method to save the player data before starting the game. The “val” method retrieves the data as a JSON object. There are two possibilities for this data: if it is the first time this player authenticates, the data will be null, and we need to initialize it with the default values. Otherwise, we simply save the data from the database. In the end, we start the game as before.

Pokemon.TitleState.prototype.start_game = function (snapshot) {
    "use strict";
    var user_data;
    user_data = snapshot.val();
    if (!user_data) {
        this.game.caught_pokemon = [];
        this.number_of_pokeballs = {pokeball: 0, greatball: 1, ultraball: 2};
    } else {
        this.game.caught_pokemon = user_data.caught_pokemon || [];
        this.game.number_of_pokeballs = user_data.number_of_pokeballs || {pokeball: 0, greatball: 1, ultraball: 2};
    }
    this.game.state.start("BootState", true, false, "assets/levels/world_level.json", "WorldState");
};

The last thing we have to do is update Firebase every time this data changes. This is done in the Pokeball and Pokemon prefabs.

In the “throw” method of the Pokeball prefab we need to update the “number_of_pokeballs” object in the database every time a pokeball is used. We do that by navigating to this object and calling the “set” method, which replaces the object in the database with a new one.

Pokemon.Pokeball.prototype.throw = function () {
    "use strict";
    var distance_to_initial_position;
    
    // stop draggin the pokeball
    this.dragging = false;
    
    // throw the pokeball if the distance to the initial position is above the threshold
    distance_to_initial_position = new Phaser.Point(this.x - this.initial_position.x, this.y - this.initial_position.y);
    if (distance_to_initial_position.getMagnitude() > this.THROW_THRESHOLD) {
        this.game_state.game.number_of_pokeballs[this.type] -= 1;
        // update database
        firebase.database().ref("/users/" + firebase.auth().currentUser.uid + "/number_of_pokeballs").set(this.game_state.game.number_of_pokeballs);
        this.number_of_pokeballs_text.text = this.game_state.game.number_of_pokeballs[this.type];
        distance_to_initial_position.normalize();
        // initialize the pokeball physical body
        this.init_body();
        this.body.velocity.x = -distance_to_initial_position.x * this.pokeball_speed;
        this.body.velocity.y = -distance_to_initial_position.y * this.pokeball_speed;
    } else {
        this.reset(this.initial_position.x, this.initial_position.y);
    }
};

Similarly, in the “catch” method of Pokemon prefab we update the “caught_pokemon” object every time a new Pokemon is caught.

Pokemon.Pokemon.prototype.catch = function () {
    "use strict";
    var catch_message;
    // kill the Pokemon and show the catch message box
    this.kill();
    
    if (!this.already_caught()) {    
        this.game_state.game.caught_pokemon.push({species: this.species, texture: this.texture_key});
        // update database
        firebase.database().ref("/users/" + firebase.auth().currentUser.uid + "/caught_pokemon").set(this.game_state.game.caught_pokemon);
    }
    
    catch_message = new Pokemon.MessageBox(this.game_state, "catch_message", {x: this.game_state.game.world.centerX, y: this.game_state.game.world.centerY}, this.MESSAGE_PROPERTIES);
    catch_message.message_text.text = "Gotcha!";
};

Finally, we need to remove the default data initialization from main.js.

Now you can try playing the game with the database feature. Try catching some Pokemon and throwing some pokeballs to see if the data is updated when the game restarts.

And this concludes this tutorial series. I hope you liked it, and leave in the comment section suggestions for the next ones!

]]>
How to Create a Pokemon GO Game – Part 3 https://gamedevacademy.org/how-to-create-a-pokemon-go-game-part-3/ Thu, 27 Oct 2016 04:04:05 +0000 https://gamedevacademy.org/?p=4257 Read more]]> In the last tutorial we added the Trainer and different Pokemon species to our game. Now we are going to limit the number of pokeballs for the player, and add different types of pokeball with different catching rates. To get new pokeballs the player will have to interact with pokestops. The following topics will be covered in this tutorial:

  • Limiting the number of pokeballs
  • Adding different types of pokeball with different catching rates
  • Adding pokestops where the player can collect pokeballs
  • Adding a title screen

To read this tutorial, it is important that you are familiar with the following concepts:

  • Javascript and object-oriented concepts.
  • Basic Phaser concepts, such as: states, sprites, groups and arcade physics
  • Creating maps using Tiled

Become a Game Developer by building 15 games

If you want to master Phaser and learn how to publish Phaser games as native games for iOS and Android feel free to check Zenva‘s online course The Complete Mobile Game Development Course – Build 15 Games.

Source code files

You can download the tutorial source code files here.

Limiting the number of pokeballs

The first thing towards limiting the number of pokeballs is initializing it in main.js. Since it will be used by different game states, we will save it in the game object.

var Pokemon = Pokemon || {};


var game = new Phaser.Game(320, 640, Phaser.CANVAS);

game.caught_pokemon = [];
game.number_of_pokeballs = 0;

game.state.add("BootState", new Pokemon.BootState());
game.state.add("LoadingState", new Pokemon.LoadingState());
game.state.add("TitleState", new Pokemon.TitleState());
game.state.add("WorldState", new Pokemon.WorldState());
game.state.add("CatchState", new Pokemon.CatchState());
game.state.start("BootState", true, false, "assets/levels/title_screen.json", "TitleState");

Now, in the CatchState we want to show the current number of pokeballs below the pokeball prefab. We can do that by creating a TextPrefab below the pokeball, and setting its text to be the current number of pokeballs. This is done in the end of the constructor of the Pokeball Prefab.

text_position = new Phaser.Point(this.x, this.y + this.height * 0.7);
    this.number_of_pokeballs_text = new Pokemon.TextPrefab(this.game_state, "number_of_pokeballs", text_position, this.TEXT_PROPERTIES);
    this.number_of_pokeballs_text.text = this.game_state.game.number_of_pokeballs;

We need to keep this text updated. So, after throwing a Pokeball we need to decrease the number of pokeballs and update the text.

Pokemon.Pokeball.prototype.throw = function () {
    "use strict";
    var distance_to_initial_position;
    
    // stop draggin the pokeball
    this.dragging = false;
    
    // throw the pokeball if the distance to the initial position is above the threshold
    distance_to_initial_position = new Phaser.Point(this.x - this.initial_position.x, this.y - this.initial_position.y);
    if (distance_to_initial_position.getMagnitude() > this.THROW_THRESHOLD) {
        this.game_state.game.number_of_pokeballs -= 1;
        this.number_of_pokeballs_text.text = this.game_state.game.number_of_pokeballs;
        distance_to_initial_position.normalize();
        // initialize the pokeball physical body
        this.init_body();
        this.body.velocity.x = -distance_to_initial_position.x * this.pokeball_speed;
        this.body.velocity.y = -distance_to_initial_position.y * this.pokeball_speed;
    } else {
        this.reset(this.initial_position.x, this.initial_position.y);
    }
};

Also, if the Pokemon is not caught after throwing the Pokeball, we reset the Pokeball to its initial position. We are going to override the reset method to also check if this was the last pokeball. If so, we need to return to WorldState.

Pokemon.Pokeball.prototype.reset = function (x, y) {
    "use strict";
    Phaser.Sprite.prototype.reset.call(this, x, y);
    
    if (this.game_state.game.number_of_pokeballs === 0) {
        this.game_state.return_to_world();
    }
};

Before moving on we need to change the PokemonSpawn prefab to only start CatchState if the current number of pokeballs is greater than zero.

Pokemon.PokemonSpawn.prototype.try_catching = function () {
    "use strict";
    // start CatchState
    if (this.game_state.game.number_of_pokeballs > 0) {
        this.game_state.game.state.start("BootState", true, false, "assets/levels/catch_level.json", "CatchState", {pokemon_properties: this.pokemon_properties});
    }
};

By now you can try playing and checking if CatchState is showing the current number of pokeballs. Try losing all pokeballs to see if it returns to WorldState. Also, try clicking in a PokemonSpawn without pokeballs.

number_of_pokeballs

Adding different types of pokeball

Now that we are limiting the number of pokeballs, let’s add different types of pokeball.

First, let’s change the number of pokeballs to be an object with three different types of pokeball: pokeball, greatball and ultraball.

game.number_of_pokeballs = this.game.number_of_pokeballs || {pokeball: 0, greatball: 1, ultraball: 2};

The other parts of code that use this variable also need to be changed.

For example, in the PokemonSpawn prefab we need to check if the sum of all pokeballs is greater than zero.

Pokemon.PokemonSpawn.prototype.try_catching = function () {
    "use strict";
    // start CatchState
    if (this.game_state.game.number_of_pokeballs.pokeball +
        this.game_state.game.number_of_pokeballs.greatball +
        this.game_state.game.number_of_pokeballs.ultraball > 0) {
        this.game_state.game.state.start("BootState", true, false, "assets/levels/catch_level.json", "CatchState", {pokemon_properties: this.pokemon_properties});
    }
};

In the Pokeball prefab we need to add a “type” property. This property will be used to access the “number_of_pokeballs” object. Also, now in the “reset” method we are going to return to WorldState only if the sum of all pokeballs is zero. If the player is out of only the current pokeball, we change its alpha to 0.5.

this.type = properties.type;

this.number_of_pokeballs_text.text = this.game_state.game.number_of_pokeballs[this.type];

if (this.game_state.game.number_of_pokeballs[this.type] === 0) {
        this.alpha = 0.5;
}
Pokemon.Pokeball.prototype.reset = function (x, y) {
    "use strict";
    Phaser.Sprite.prototype.reset.call(this, x, y);
    
    if (this.game_state.game.number_of_pokeballs[this.type] === 0) {
        this.alpha = 0.5;
    }
    
    if (this.game_state.game.number_of_pokeballs.pokeball +
            this.game_state.game.number_of_pokeballs.greatball +
            this.game_state.game.number_of_pokeballs.ultraball === 0) {
        this.game_state.return_to_world();
    }
};

Now, in the CatchState level file (catch_level.json) we are going to add the three types of pokeball, each one with its own “type” and “catching_rate” properties. Also, we are going to add a Button prefab called “switch_pokeball”, which will call a “switch_pokeball” method in CatchState.

"pokeball": {
            "type": "pokeball",
            "position": {"x": 0.5, "y": 0.8},
            "properties": {
                "texture": "pokeball_image",
                "group": "pokeballs",
                "anchor": {"x": 0.5, "y": 0.5},
                "pokeball_speed": 300,
                "catching_rate": 0.5,
                "type": "pokeball"
            }
        },
        "greatball": {
            "type": "pokeball",
            "position": {"x": 0.5, "y": 0.8},
            "properties": {
                "texture": "greatball_image",
                "group": "pokeballs",
                "anchor": {"x": 0.5, "y": 0.5},
                "pokeball_speed": 300,
                "catching_rate": 0.75,
                "type": "greatball"
            }
        },
        "ultraball": {
            "type": "pokeball",
            "position": {"x": 0.5, "y": 0.8},
            "properties": {
                "texture": "ultraball_image",
                "group": "pokeballs",
                "anchor": {"x": 0.5, "y": 0.5},
                "pokeball_speed": 300,
                "catching_rate": 0.9,
                "type": "ultraball"
            }
        },
        "switch_pokeball": {
            "type": "button",
            "position": {"x": 0.5, "y": 0.95},
            "properties": {
                "texture": "pokeball_image",
                "group": "hud",
                "anchor": {"x": 0.5, "y": 0.5},
                "scale": {"x": 0.4, "y": 0.4},
                "callback": "switch_pokeball"
            }
        }

Now we need to implement the logic to switch pokeballs. First, we are going to add an “enable” method to the Pokeball prefab. This method will be called when switching a pokeball, and will change the “visible”, “inputEnabled” and “checkWorldBounds” properties. The idea is to make a pokeball visible if it is the current one. Also, we need to enable its events only if its the current one and the number of pokeballs of its type is greater than zero. By default, all pokeballs are disabled in the constructor.

Pokemon.Pokeball.prototype.enable = function (enable) {
    "use strict";
    this.visible = enable;
    this.inputEnabled = enable && (this.game_state.game.number_of_pokeballs[this.type] > 0);
    this.checkWorldBounds = enable && (this.game_state.game.number_of_pokeballs[this.type] > 0);
    this.number_of_pokeballs_text.visible = enable;
};

Finally, we need to implement the “switch_pokeball” method in CatchState. But first, in the end of the “create” method we are going to add one array with the pokeball types and one variable with the index of the current one. Then, we enable the first pokeball.

this.pokeball_types = ["pokeball", "greatball", "ultraball"];
    this.current_pokeball_index = 0;
    this.prefabs[this.pokeball_types[this.current_pokeball_index]].enable(true);

Now the “switch_pokeball” method will simply disable the current pokeball, increment the index (limited by the “pokeball_types” array size) and enable the next pokeball.

Pokemon.CatchState.prototype.switch_pokeball = function () {
    "use strict";
    this.prefabs[this.pokeball_types[this.current_pokeball_index]].enable(false);
    this.current_pokeball_index = (this.current_pokeball_index + 1) % this.pokeball_types.length;
    this.prefabs[this.pokeball_types[this.current_pokeball_index]].enable(true);
};

By now you can try playing and switching pokeballs. Notice that each pokeball type has its own texture, so you can easily see that they are changing.

types_of_pokeball

Adding pokestops

The next step is adding pokestops where the player can collect new pokeballs.

So, let’s start by creating a Pokestop prefab. In the constructor we need to save its properties such as “reset_time” and “detection_radius”. We also are going to add an input event to collect pokeballs and create a reset timer, which will be dispatched after every input event.

Pokemon.Pokestop = function (game_state, name, position, properties) {
    "use strict";
    var text_position;
    Pokemon.Prefab.call(this, game_state, name, position, properties);
    
    this.INITIAL_POKEBALL_POSITION = new Phaser.Point(this.game_state.game.width - 50, 50);
    this.POKEBALL_TIME = 2;
    
    this.reset_time = +properties.reset_time;
    this.detection_radius = +properties.detection_radius;
    
    this.events.onInputDown.add(this.get_pokeballs, this);
    
    this.reset_timer = this.game_state.game.time.create(false);
};

The “update” method will check if the trainer is close to the pokestop, similarly to what we did with the PokemonSpawn. The only difference is that now we are only going to change the “inputEnabled” property, and the pokestop will be always visible.

Pokemon.Pokestop.prototype.update = function () {
    "use strict";
    var distance_to_trainer, trainer_within_detection_radius;
    distance_to_trainer = this.position.distance(this.game_state.prefabs.trainer.position);
    trainer_within_detection_radius = distance_to_trainer <= this.detection_radius;
    this.inputEnabled = trainer_within_detection_radius;
};

The “get_pokeballs” method needs to randomly choose the type and number of pokeballs the player will collect. This will be similar to what we are already doing to spawn Pokemon. So, first we are going to move the code that choose a random Pokemon to the Utils.js file, and put it in a function called “choose_randomly”. This method will generate a random number and pick the first element in an array whose probability is greater than the generated random number.

Pokemon.choose_randomly = function (rnd, probabilities) {
    "use strict";
    var random_number, element_index, element;
    random_number = rnd.frac();
    for (element_index = 0; element_index < probabilities.length; element_index += 1) {
        element = probabilities[element_index];
        if (random_number < element.probability) {
            return element;
        }
    }
};

Now, the “get_pokeballs” method will simply make use of this function. First, we are going to change the pokestop tint, to show that it has been used. Then we randomly choose a number of pokeballs to spawn, from an array containing this probabilities. Then, for each collected pokeball, we randomly choose its type, from another array of probabilities. In the end we disable the input events, call a method to show the collected pokeballs and dispatch the reset timer.

Pokemon.Pokestop.prototype.get_pokeballs = function () {
    "use strict";
    var number_of_pokeballs, pokeball_index, pokeball, pokeballs_to_show;
    
    this.tint = 0xff0000;
    
    number_of_pokeballs = Pokemon.choose_randomly(this.game_state.rnd, this.game_state.pokeball_probabilities.number_of_pokeballs);
    
    pokeballs_to_show = [];
    for (pokeball_index = 0; pokeball_index < number_of_pokeballs.number; pokeball_index += 1) {
        pokeball = Pokemon.choose_randomly(this.game_state.rnd, this.game_state.pokeball_probabilities.type_of_pokeball);
        this.game_state.game.number_of_pokeballs[pokeball.type] += 1;
        pokeballs_to_show.push(pokeball.type);
    }

    this.inputEnabled = false;
    
    this.show_pokeballs(pokeballs_to_show);
    
    this.reset_timer.add(this.reset_time * Phaser.Timer.SECOND, this.reset_pokestop, this);
    this.reset_timer.start();
};

The “show_pokeballs” method will create a Phaser.Sprite for each collected pokeball, so that the player can see what he collected. For each sprite we are going to add an event which will kill it after some time.

Pokemon.Pokestop.prototype.show_pokeballs = function (pokeballs_to_show) {
    "use strict";
    var pokeball_index, pokeball_position, pokeball, pokeball_kill_timer;
    pokeball_position = new Phaser.Point(this.INITIAL_POKEBALL_POSITION.x, this.INITIAL_POKEBALL_POSITION.y);
    pokeball_kill_timer = this.game_state.game.time.create();
    pokeballs_to_show.forEach(function(pokeball_type) {
        pokeball = new Phaser.Sprite(this.game_state.game, pokeball_position.x, pokeball_position.y, pokeball_type + "_image");
        pokeball.anchor.setTo(0.5);
        pokeball.scale.setTo(0.3);
        this.game_state.groups.hud.add(pokeball);
        
        pokeball_kill_timer.add(this.POKEBALL_TIME * Phaser.Timer.SECOND, pokeball.kill, pokeball);
        
        pokeball_position.y += 1.5*pokeball.height;
    }, this);
    pokeball_kill_timer.start();
};

The “reset_pokestop” method, by its turn, will simply restore the tint value, enable input events and stop the “reset_timer”.

Pokemon.Pokestop.prototype.reset_pokestop = function () {
    "use strict";
    this.inputEnabled = true;
    this.tint = 0xffffff;
    this.reset_timer.stop();
};

Now we need to create the probabilities arrays and add them to our “game_state”. The probabilities will be saved in a “pokeball_probabilities.json” file like the following one. There will be two arrays: one for the number of pokeballs and one for the type of each pokeball.

{
    "number_of_pokeballs": [
        {"number": 3, "probability": 0.2},
        {"number": 2, "probability": 0.5},
        {"number": 1, "probability": 1.0}
    ],
    "type_of_pokeball": [
        {"type": "pokeball", "probability": 0.5},
        {"type": "greatball", "probability": 0.8},
        {"type": "ultraball", "probability": 1.0}
    ]
}

Then, in the “preload” method of WorldState we need to load this text file. Also, in the end of the “create” method we need to parse it as a JSON file and save it in a “pokeball_probabilities” object.

Pokemon.WorldState.prototype.preload = function () {
    "use strict";
    this.load.text("pokemon_probabilities", this.level_data.pokemon_probabilities);
    this.load.text("pokeball_probabilities", this.level_data.pokeball_probabilities);
};
this.pokeball_probabilities = JSON.parse(this.game.cache.getText("pokeball_probabilities"));

By now, you can try adding a pokestop in your Tiled map and try collecting some pokeballs. Try different configurations of probabilities to check if its working correctly. Also, try collecting pokeballs when the trainer is too far away and when the pokestop is still resetting, to see if it works.

pokestop

Adding title screen

The last thing we are going to add is a title screen for our game. This will be a very simple one, which will only show the game title and will have an input event to start the game.

TitleState will also be loaded from a JSON file like CatchState. So, we are going to create a JSONLevelState which will be responsible for doing that. Then, both CatchState and TitleState will extend it, implementing only the different things. The JSONLevelState will only save the level data, set the game scale, create groups and prefabs.

var Pokemon = Pokemon || {};

Pokemon.JSONLevelState = function () {
    "use strict";
    Phaser.State.call(this);
    
    this.prefab_classes = {
        
    };
};

Pokemon.JSONLevelState.prototype = Object.create(Phaser.State.prototype);
Pokemon.JSONLevelState.prototype.constructor = Pokemon.JSONLevelState;

Pokemon.JSONLevelState.prototype.init = function (level_data, extra_parameters) {
    "use strict";
    this.level_data = level_data;
    
    this.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
    this.scale.pageAlignHorizontally = true;
    this.scale.pageAlignVertically = true;
};

Pokemon.JSONLevelState.prototype.create = function () {
    "use strict";
    var group_name, prefab_name, pokemon_data;
    
    // create groups
    this.groups = {};
    this.level_data.groups.forEach(function (group_name) {
        this.groups[group_name] = this.game.add.group();
    }, this);
    
    // create prefabs
    this.prefabs = {};
    for (prefab_name in this.level_data.prefabs) {
        if (this.level_data.prefabs.hasOwnProperty(prefab_name)) {
            // create prefab
            this.create_prefab(prefab_name, this.level_data.prefabs[prefab_name]);
        }
    }
};

Pokemon.JSONLevelState.prototype.create_prefab = function (prefab_name, prefab_data) {
    "use strict";
    var prefab_position, prefab;
    // create object according to its type
    if (this.prefab_classes.hasOwnProperty(prefab_data.type)) {
        if (prefab_data.position.x > 0 && prefab_data.position.x <= 1) {
            // position as percentage
            prefab_position = new Phaser.Point(prefab_data.position.x * this.game.world.width,
                                              prefab_data.position.y * this.game.world.height);
        } else {
            // position as absolute number
            prefab_position = prefab_data.position;
        }
        prefab = new this.prefab_classes[prefab_data.type](this, prefab_name, prefab_position, prefab_data.properties);
    }
    return prefab;
};

Now CatchState will only implement its specific behavior, such as: creating the Pokemon prefab, controlling the current pokeball type, and returning to WorldState.

var Pokemon = Pokemon || {};

Pokemon.CatchState = function () {
    "use strict";
    Pokemon.JSONLevelState.call(this);
    
    this.prefab_classes = {
        "background": Pokemon.Prefab.prototype.constructor,
        "pokeball": Pokemon.Pokeball.prototype.constructor,
        "pokemon": Pokemon.Pokemon.prototype.constructor,
        "button": Pokemon.Button.prototype.constructor
    };
};

Pokemon.CatchState.prototype = Object.create(Pokemon.JSONLevelState.prototype);
Pokemon.CatchState.prototype.constructor = Pokemon.CatchState;

Pokemon.CatchState.prototype.init = function (level_data, extra_parameters) {
    "use strict";
    Pokemon.JSONLevelState.prototype.init.call(this, level_data, extra_parameters);
    
    // start physics system
    this.game.physics.startSystem(Phaser.Physics.P2JS);
    this.game.physics.arcade.gravity.y = 0;
    
    this.pokemon_properties = extra_parameters.pokemon_properties;
};

Pokemon.CatchState.prototype.create = function () {
    "use strict";
    var pokemon_data;
    
    this.collision_groups = {};
    this.level_data.collision_groups.forEach(function (collision_group_name) {
        this.collision_groups[collision_group_name] = this.game.physics.p2.createCollisionGroup();
    }, this);
    
    Pokemon.JSONLevelState.prototype.create.call(this);
    
    pokemon_data = {
        type: "pokemon",
        position: {x: 0.5, y: 0.6},
        properties: this.pokemon_properties
    }
    this.create_prefab("pokemon", pokemon_data);
    
    this.pokeball_types = ["pokeball", "greatball", "ultraball"];
    this.current_pokeball_index = 0;
    this.prefabs[this.pokeball_types[this.current_pokeball_index]].enable(true);
};

Pokemon.CatchState.prototype.return_to_world = function () {
    "use strict";
    this.game.state.start("BootState", true, false, "assets/levels/world_level.json", "WorldState");
};

Pokemon.CatchState.prototype.switch_pokeball = function () {
    "use strict";
    this.prefabs[this.pokeball_types[this.current_pokeball_index]].enable(false);
    this.current_pokeball_index = (this.current_pokeball_index + 1) % this.pokeball_types.length;
    this.prefabs[this.pokeball_types[this.current_pokeball_index]].enable(true);
};

Now, TitleState will simply add an input event in the end of the “create” method. This event will start WorldState, in order to start the game.

var Pokemon = Pokemon || {};

Pokemon.TitleState = function () {
    "use strict";
    Pokemon.JSONLevelState.call(this);
    
    this.prefab_classes = {
        "text": Pokemon.TextPrefab.prototype.constructor
    };
};

Pokemon.TitleState.prototype = Object.create(Pokemon.JSONLevelState.prototype);
Pokemon.TitleState.prototype.constructor = Pokemon.TitleState;

Pokemon.TitleState.prototype.create = function () {
    "use strict";
    var pokemon_data;
    Pokemon.JSONLevelState.prototype.create.call(this);
    
    this.game.input.onDown.add(this.start_game, this);
};

Pokemon.TitleState.prototype.start_game = function () {
    "use strict";
    this.game.state.start("BootState", true, false, "assets/levels/world_level.json", "WorldState");
};

The last thing we have to do is creating the JSON file for TitleState. This level will only have the title message and a start message.

{
    "assets": {
        
    },
    "groups": [
        "hud"
    ],
    "prefabs": {
        "title": {
            "type": "text",
            "position": {"x": 0.5, "y": 0.5},
            "properties": {
                "anchor": {"x": 0.5, "y": 0.5},
                "group": "hud",
                "text": "Phasermon GO",
                "style": {"font": "32px Arial", "fill": "#FFF"}
            }
        },
        "start_message": {
            "type": "text",
            "position": {"x": 0.5, "y": 0.7},
            "properties": {
                "anchor": {"x": 0.5, "y": 0.5},
                "group": "hud",
                "text": "Tap screen to start",
                "style": {"font": "20px Arial", "fill": "#FFF"}
            }
        }
    }
}

By now you can try playing the game with the title screen, and checking if its’s correctly starting the game.

title_screen

And that concludes this tutorial. In the next (and last) one, we are going to save the player pokeballs and caught Pokemon in an online database. Also, we will need to add authentication in order to access the saved data.

]]>
The Complete Mobile Game Development Course – Platinum Edition https://gamedevacademy.org/the-complete-mobile-game-development-course-platinum-edition/ Mon, 10 Oct 2016 12:00:28 +0000 https://gamedevacademy.org/?p=3691 Read more]]> This is THE course to get you on the road to becoming a game developer. You will learn by creating Real-World projects and at the end of the course you will have 15 mobile games that you have built from the ground up.

As you work through this course, you’ll build  apps using JavaScript and the free  HTML5 Phaser library . You’ll learn how to publish them to Apple,  Google,  and  Amazon’s app store using Cordova and the Intel XDK. you will learn how to monetize your games and apps with ads and in-app purchases so you can start making money.

Besides making games you’ll also gain valuable app and web development skills

  • Become a proficient JavaScript and HTML5 developer.
  • Understand the hybrid app development process.
  • How to publish to the iOS and Android platforms using the Intel XDK.
  • How to use the Intel XDK to emulate and test remotely.
  • Monetize your games and apps with ads and in-app purchases.

Access this course on Zenva Academy

]]>
Phaser Game Templates – Pack 1 https://gamedevacademy.org/phaser-game-templates-pack-1/ Tue, 04 Oct 2016 12:19:23 +0000 https://gamedevacademy.org/?p=4118 Read more]]> Need a game and  you have a crazy deadline? Here is your solution! Get 5 ready to use Phaser Game templates from Richard Davey.  The Phaser Games Pack 1 is a collection of 5 complete Phaser game templates that are ready to go.

These templates are free to use for personal or commercial projects and include:

Black Jack Coloring Book Jigsaw Puzzle Word Search

Each template contains the full source code, which is heavily commented. The games were created with Phaser 2.6.2., the absolute latest version. You will receive:

  • 5 fully commented Game Templates
  • BlackJack – The casino card game
  • Coloring Book + Flood Fill Plugin
  • Jigsaw + Piece Cutter Plugin
  • Sliding Puzzle – With solver
  • Word Search + Plugin
  • Commercial use allowed
  • 10 Page Guide + PSDs

Get The Phaser Games Pack Now!

]]>
How to Create a Pokemon GO Game – Part 2 https://gamedevacademy.org/how-to-create-a-pokemon-go-game-part-2/ Mon, 03 Oct 2016 00:15:43 +0000 https://gamedevacademy.org/?p=4181 Read more]]> In the last tutorial we created the basic Phaser states for our game. Now, we are going to add the Trainer in the WorldState, and change our game to regularly spawn Pokemon. The following topics will be covered in this tutorial:

In this first tutorial I will cover the following content:

  • Creating a Trainer prefab to walk around the World
  • Creating a prefab to regularly spawn Pokemon in the World
  • Adding different species of Pokemon with different probabilities
  • Saving the Pokemon caught by the trainer, which are shown in its Pokedex

To read this tutorial, it is important that you are familiar with the following concepts:

  • Javascript and object-oriented concepts.
  • Basic Phaser concepts, such as: states, sprites, groups and arcade physics
  • Creating maps using Tiled

Learn Phaser by building 15 games

If you want to master Phaser and learn how to publish Phaser games as native games for iOS and Android feel free to check Zenva‘s online course The Complete Mobile Game Development Course – Build 15 Games.

Source code files

You can download the tutorial source code files here.

Trainer prefab

Let’s start by creating the Trainer prefab. In the original Pokemon GO game the Trainer walks according to your GPS position. However, in this series we are only going to make it walk towards a desired position obtained when the player clicks (or touches) the screen.

In order to do that, in the constructor we need to save its walking speed, define its animations, initialize its physical body and the input event to move the Trainer.

Pokemon.Trainer = function (game_state, name, position, properties) {
    "use strict";
    var rotate_tween;
    Pokemon.Prefab.call(this, game_state, name, position, properties);
    
    this.walking_speed = +properties.walking_speed;
    
    this.animations.add("walking_down", [0, 1, 2, 3], 10, true);
    this.animations.add("walking_up", [4, 5, 6, 7], 10, true);
    this.animations.add("walking_right", [8, 9, 10, 11], 10, true);
    this.animations.add("walking_left", [12, 13, 14, 15], 10, true);
    
    this.stopped_frames = [0, 8, 12, 4, 0];
    
    this.game_state.game.physics.p2.enable(this);
    
    this.game_state.game.input.onDown.add(this.move_to, this);
    
    this.target_position = new Phaser.Point(this.position.x, this.position.y);
};

The “move_to” method will simply set a new target position for the Trainer.

Pokemon.Trainer.prototype.move_to = function (pointer) {
    "use strict";
    this.target_position.x = Math.round(pointer.position.x);
    this.target_position.y = Math.round(pointer.position.y);
};

Now the update method is the one responsible for moving the Trainer. This method starts by checking if the Trainer has to move on the y coordinate, by comparing its current y coordinate to the y coordinate of the target position. If so, we set its velocity in the y direction. Next, we do the same for the x coordinate. If no movement is necessary, we set the velocity for 0.

Finally, we play the correct animation accordingly to the Trainer velocity. If the velocity is 0 in both directions, we stop the current animation and set the current frame to the appropriate stopped frame, using the facing property of the physical body.

Pokemon.Trainer.prototype.update = function () {
    "use strict";
    var direction_y, direction_x;
    
    if (Math.abs(this.position.y - this.target_position.y) > 1) {
        direction_y = (this.position.y < this.target_position.y) ? 1 : -1;
        this.body.velocity.x = 0;
        this.body.velocity.y = direction_y * this.walking_speed;
    } else if (Math.abs(this.position.x - this.target_position.x) > 1) {
        direction_x = (this.position.x < this.target_position.x) ? 1 : -1;
        this.body.velocity.x = direction_x * this.walking_speed;
        this.body.velocity.y = 0;
    } else {
        this.body.velocity.x = 0;
        this.body.velocity.y = 0;
    }
    
    if (this.body.velocity.y > 0) {
        this.animations.play("walking_down");
    } else if (this.body.velocity.y < 0) {
        this.animations.play("walking_up");
    } else if (this.body.velocity.x > 0) {
        this.animations.play("walking_right");
    } else if (this.body.velocity.x < 0) {
        this.animations.play("walking_left");
    } else {
        this.animations.stop();
        this.frame = this.stopped_frames[this.body.facing];
    }
};

By now, you can already try adding the Trainer to the Tiled map of WorldState. You only need to remember to add the Trainer prefab to the “prefab_classes” property in WorldState.

trainer

PokemonSpawner prefab

The next step is to spawn Pokemon around the world map.

First, we will change the PokemonSpawn prefab. Until now, this prefab only had an input event to start the CatchState. We are going to change it to make it visible only when the Trainer is close, and kill the spawn after some time.

So, in the constructor we need to save the PokemonSpawn duration and detection radius. Then, we initially set it as invisible and start the kill event.

Pokemon.PokemonSpawn = function (game_state, name, position, properties) {
    "use strict";
    Pokemon.Prefab.call(this, game_state, name, position, properties);
    
    this.anchor.setTo(0.25);
    this.scale.setTo(0.25);
    
    this.duration = properties.duration;
    this.detection_radius = properties.detection_radius;
    
    this.visible = false;
    
    this.add_kill_event();
    
    // add input event to try catching this Pokemon
    this.events.onInputDown.add(this.try_catching, this);
};

The “add_kill_event” method start a timer with a random duration which will kill the spawn after some time. The random duration is obtained between the minimum and maximum values in the duration property.

Pokemon.PokemonSpawn.prototype.add_kill_event = function () {
    "use strict";
    var duration;
    duration = this.game_state.rnd.between(this.duration.min, this.duration.max);
    this.kill_timer = this.game_state.time.create();
    this.kill_timer.add(Phaser.Timer.SECOND * duration, this.kill, this);
};

The “update” method, by its turn, will check if the Trainer is close to the PokemonSpawn, in order to show it. We do that by measuring the distance between those two prefabs. If this distance is less than the detection radius we make the spawn visible and enable its inputs, so that now the player can catch it.

Pokemon.PokemonSpawn.prototype.update = function () {
    "use strict";
    var distance_to_trainer, trainer_within_detection_radius;
    distance_to_trainer = this.position.distance(this.game_state.prefabs.trainer.position);
    trainer_within_detection_radius = distance_to_trainer <= this.detection_radius;
    this.visible = trainer_within_detection_radius;
    this.inputEnabled = trainer_within_detection_radius;
};

Now we are going to create a PokemonSpawner prefab, which will actually create PokemonSpawn on the map.

In order to do that we need to save in the constructor the following properties: the default properties of spawns in order to create them, the minimum and maximum spawn times in order to create a spawn timer, and a spawn distance range. In the end we create a spawn timer and call a method to schedule its next event.

Pokemon.PokemonSpawner = function (game_state, name, position, properties) {
    "use strict";
    Pokemon.Prefab.call(this, game_state, name, position, properties);
    
    this.DEFAULT_SPAWN_PROPERTIES = {
        texture: "",
        group: "spawns",
        duration: {min: 30, max: 60},
        detection_radius: 50
    };
    
    this.spawn_time_min = +properties.spawn_time_min;
    this.spawn_time_max = +properties.spawn_time_max;
    this.spawn_range = +properties.spawn_range;
    
    this.spawn_timer = this.game_state.time.create(false);
    this.schedule_spawn();
};

The “schedule_spawn” method pick a random number between the minimum and maximum spawn times and add a new event with this duration. This event will call the “spawn” method, which will create a new PokemonSpawn.

Pokemon.PokemonSpawner.prototype.schedule_spawn = function () {
    "use strict";
    var time;
    // add a new spawn event with random time between a range
    time = this.game_state.rnd.between(this.spawn_time_min, this.spawn_time_max);
    this.spawn_timer.add(Phaser.Timer.SECOND * time, this.select_pokemon, this);
    this.spawn_timer.start();
};

In order to create new spawn, we are going to use a method defined in a different file (Utils.js) that creates a prefab from a pool. The idea is to get the first dead prefab from the pool and creating a new prefab only if there is no dead one to reuse. If there is already a dead prefab, we simply reset it to the desired position.

Pokemon.create_prefab_from_pool = function (pool, prefab_constructor, game_state, prefab_name, prefab_position, prefab_properties) {
    "use strict";
    var prefab;
    // get the first dead prefab from the pool
    prefab = pool.getFirstDead();
    if (!prefab) {
        // if there is no dead prefab, create a new one
        prefab = new prefab_constructor(game_state, prefab_name, prefab_position, prefab_properties);
    } else {
        // if there is a dead prefab, reset it in the new position
        prefab.reset(prefab_position.x, prefab_position.y);
    }
    return prefab;
};

So, in the “spawn” method, we simply need to define the pool, the prefab name, its position and properties, in order to call the “create_prefab_from_pool” method. Notice that the position is calculated by picking a random distance from the spawner using the “spawn_range” property. After spawning another pokemon, we call the “schedule_spawn” method again, to schedule the next event.

Pokemon.PokemonSpawner.prototype.spawn = function (pokemon_data) {
    "use strict";
    var pool, spawn_name, distance, spawn_position, spawn_properties;
    pool = this.game_state.groups.spawns;
    spawn_name = this.name + "_spawn_" + pool.countLiving() + pool.countDead();
    distance = new Phaser.Point(this.game_state.rnd.between(-this.spawn_range, this.spawn_range), this.game_state.rnd.between(-this.spawn_range, this.spawn_range));
    spawn_position = new Phaser.Point(this.x + distance.x, this.y + distance.y);
    spawn_properties = Object.create(this.DEFAULT_SPAWN_PROPERTIES);
    spawn_properties.texture = pokemon_data.properties.texture;
    spawn_properties.pokemon_properties = pokemon_data.properties;
    Pokemon.create_prefab_from_pool(pool, Pokemon.PokemonSpawn.prototype.constructor, this.game_state, spawn_name, spawn_position, spawn_properties);
    
    this.schedule_spawn();
};

By now you can already try adding a spawner to your Tiled map and see if it is correctly spawning Pokemon. Also, check if the spawns are working correctly, by showing up only when the Trainer is close to them.

spawn

Adding different species of Pokemon

Now that we are spawning Pokemon, we want to add different species of Pokemon with different spawn probabilities.

We will describe all Pokemon in a separate JSON file like the one below (if you’re curious, I pick the Pokemon name using this generator):

[
    {
        "probability": 0.3,
        "properties": {
            "texture": "draros_image",
            "group": "pokemons",
            "anchor": {"x": 0.5, "y": 0.5},
            "frame": 1,
            "fleeing_rate": 0.3,
            "species": "Draros"
        }
    },
    {
        "probability": 0.5,
        "properties": {
            "texture": "penguine_image",
            "group": "pokemons",
            "anchor": {"x": 0.5, "y": 0.5},
            "frame": 1,
            "fleeing_rate": 0.4,
            "species": "Penguine"
        }
    },
    {
        "probability": 1.0,
        "properties": {
            "texture": "spinron_image",
            "group": "pokemons",
            "anchor": {"x": 0.5, "y": 0.5},
            "frame": 1,
            "fleeing_rate": 0.5,
            "species": "Spinron"
        }
    }
]

This file is read in the “preload” method from WorldState, and parsed in the end of the “create” method.

Pokemon.WorldState.prototype.preload = function () {
    "use strict";
    this.load.text("pokemon_probabilities", this.level_data.pokemon_probabilities);
};

this.pokemon_probabilities = JSON.parse(this.game.cache.getText("pokemon_probabilities"));

Now let’s change the PokemonSpawn and PokemonSpawner prefabs to support different species.

In the PokemonSpawn prefab we simply need to add a new property called “pokemon_properties”, which will have the properties specific to that species (obtained from the JSON file. Then, the “try_catching” method will start CatchState with the “pokemon_properties” as an extra parameter.

this.pokemon_properties = properties.pokemon_properties;

Pokemon.PokemonSpawn.prototype.try_catching = function () {
    "use strict";
    // start CatchState
    this.game_state.game.state.start("BootState", true, false, "assets/levels/catch_level.json", "CatchState", {pokemon_properties: this.pokemon_properties});
};

In the PokemonSpawner prefab we need to select the pokemon species before spawning it. So, the spawn timer now will call a “select_pokemon” method, which will pick a random number between 0 and 1. This number will be used to select the species to be spawned. We can do that by iterating through all species and choosing the first one whose probability is larger than the generated number (as long as the species probabilities are sorted in ascending order). After choosing the species, we call the “spawn” method. We also need to change the “spawn” method to set the “pokemon_properties” property accordingly to the species.

Pokemon.PokemonSpawner.prototype.schedule_spawn = function () {
    "use strict";
    var time;
    // add a new spawn event with random time between a range
    time = this.game_state.rnd.between(this.spawn_time_min, this.spawn_time_max);
    this.spawn_timer.add(Phaser.Timer.SECOND * time, this.select_pokemon, this);
    this.spawn_timer.start();
};

Pokemon.PokemonSpawner.prototype.select_pokemon = function () {
    "use strict";
    var random_number, pokemon_index, pokemon_data;
    random_number = this.game_state.rnd.frac();
    for (pokemon_index = 0; pokemon_index < this.game_state.pokemon_probabilities.length; pokemon_index += 1) {
        pokemon_data = this.game_state.pokemon_probabilities[pokemon_index];
        if (random_number < pokemon_data.probability) {
            this.spawn(pokemon_data);
            break;
        }
    }
};

Pokemon.PokemonSpawner.prototype.spawn = function (pokemon_data) {
    "use strict";
    var pool, spawn_name, distance, spawn_position, spawn_properties;
    pool = this.game_state.groups.spawns;
    spawn_name = this.name + "_spawn_" + pool.countLiving() + pool.countDead();
    distance = new Phaser.Point(this.game_state.rnd.between(-this.spawn_range, this.spawn_range), this.game_state.rnd.between(-this.spawn_range, this.spawn_range));
    spawn_position = new Phaser.Point(this.x + distance.x, this.y + distance.y);
    spawn_properties = Object.create(this.DEFAULT_SPAWN_PROPERTIES);
    spawn_properties.texture = pokemon_data.properties.texture;
    spawn_properties.pokemon_properties = pokemon_data.properties;
    Pokemon.create_prefab_from_pool(pool, Pokemon.PokemonSpawn.prototype.constructor, this.game_state, spawn_name, spawn_position, spawn_properties);
    
    this.schedule_spawn();
};

Finally, we need to change our Phaser states to allow CatchState to receive the extra parameter. First, we change BootState and LoadingState to receive the extra parameter and simply send it to the next state.

Pokemon.BootState.prototype.init = function (level_file, next_state, extra_parameters) {
    "use strict";
    this.level_file = level_file;
    this.next_state = next_state;
    this.extra_parameters = extra_parameters;
};

Pokemon.BootState.prototype.create = function () {
    "use strict";
    var level_text, level_data;
    // parse the level file as a JSON object and send its data to LoadingState
    level_text = this.game.cache.getText("level1");
    level_data = JSON.parse(level_text);
    this.game.state.start("LoadingState", true, false, level_data, this.next_state, this.extra_parameters);
};
Pokemon.LoadingState.prototype.init = function (level_data, next_state, extra_parameters) {
    "use strict";
    this.level_data = level_data;
    this.next_state = next_state;
    this.extra_parameters = extra_parameters;
};

Pokemon.LoadingState.prototype.create = function () {
    "use strict";
    this.game.state.start(this.next_state, true, false, this.level_data, this.extra_parameters);
};

Then, in CatchState we can save the pokemon properties from the extra parameter. Now, instead of creating the Pokemon in CatchState from the JSON file, we are going to manually create it in the end of the “create” method (and remove it from the JSON file). By doing so, we can create the Pokemon with the correct properties according to its species.

Pokemon.CatchState.prototype.init = function (level_data, extra_parameters) {
    "use strict";
    this.level_data = level_data;
    
    this.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
    this.scale.pageAlignHorizontally = true;
    this.scale.pageAlignVertically = true;
    
    // start physics system
    this.game.physics.startSystem(Phaser.Physics.P2JS);
    this.game.physics.arcade.gravity.y = 0;
    
    this.pokemon_properties = extra_parameters.pokemon_properties;
};

Pokemon.CatchState.prototype.create = function () {
    "use strict";
    var group_name, prefab_name, pokemon_data;
    
    // create groups
    this.groups = {};
    this.level_data.groups.forEach(function (group_name) {
        this.groups[group_name] = this.game.add.group();
    }, this);
    
    this.collision_groups = {};
    this.level_data.collision_groups.forEach(function (collision_group_name) {
        this.collision_groups[collision_group_name] = this.game.physics.p2.createCollisionGroup();
    }, this);
    
    // create prefabs
    this.prefabs = {};
    for (prefab_name in this.level_data.prefabs) {
        if (this.level_data.prefabs.hasOwnProperty(prefab_name)) {
            // create prefab
            this.create_prefab(prefab_name, this.level_data.prefabs[prefab_name]);
        }
    }
    
    pokemon_data = {
        type: "pokemon",
        position: {x: 0.5, y: 0.6},
        properties: this.pokemon_properties
    }
    this.create_prefab("pokemon", pokemon_data);
};

By now you can try playing with different Pokemon species. Check if they are being spawned correctly, and if the Pokemon in CatchState are being properly created.

Showing the Pokedex

The last thing we are going to do in this tutorial is adding a Pokedex prefab to show the currently caught Pokemon.

In order to show the caught Pokemon we will create a PokemonSprite prefab, which will simply show the Pokemon and its species. So, in the constructor we need to create a TextPrefab, which must be killed in the “kill” method.

var Pokemon = Pokemon || {};

Pokemon.PokemonSprite = function (game_state, name, position, properties) {
    "use strict";
    Pokemon.Prefab.call(this, game_state, name, position, properties);
    var text_position;
    
    this.anchor.setTo(0.5);
    this.scale.setTo(0.25);
    
    text_position = new Phaser.Point(this.x, this.y + (this.height / 2) + 10);
    this.message_text = new Pokemon.TextPrefab(this.game_state, this.name + "_text", text_position, properties.text_properties);
    this.message_text.anchor.setTo(0.5);
};

Pokemon.PokemonSprite.prototype = Object.create(Pokemon.Prefab.prototype);
Pokemon.PokemonSprite.prototype.constructor = Pokemon.PokemonSprite;

Pokemon.PokemonSprite.prototype.kill = function () {
    "use strict";
    Phaser.Sprite.prototype.kill.call(this);
    this.message_text.kill();
};

Now the Pokedex will have the default properties for PokemonSprite, which will be changed according to the Pokemon species. In the constructor we are also going to initialize the position for the first PokemonSprite and add an input event to hide the Pokedex when it is clicked.

Pokemon.Pokedex = function (game_state, name, position, properties) {
    "use strict";
    Pokemon.Prefab.call(this, game_state, name, position, properties);
    
    this.anchor.setTo(0.5);
    
    this.DEFAULT_POKEMON_SPRITE_PROPERTIES = {
        texture: "",
        group: "pokemon_sprites",
        text_properties: {
            text: "",
            group: "hud",
            style: {
                font: "14px Arial",
                fill: "#000"
            }
        }
    };
    
    this.initial_pokemon_sprite_position = new Phaser.Point(this.x - (this.width / 2) + 50, this.y - (this.height / 2) + 50);
    
    // add input event to call game state method
    this.events.onInputDown.add(this.hide, this);
    
    this.visible = false;
};

The “show” method will make the Pokedex visible, enable its input events (so that we can hide it later), and show all caught Pokemon (saved in a “caught_pokemon” array in the game). We are going to create the PokemonSprites using the “create_prefab_from_pool” method, so we only need to define the prefab name, position and properties. Notice that we only need to change the texture and text in the default properties, while the position starts by the initial one and is updated after each iteration.

Pokemon.Pokedex.prototype.show = function () {
    "use strict";
    var pokemon_sprite, pokemon_sprite_position;
    
    this.visible = true;
    this.inputEnabled = true;
    
    pokemon_sprite_position = new Phaser.Point(this.initial_pokemon_sprite_position.x, this.initial_pokemon_sprite_position.y);
    this.game_state.game.caught_pokemon.forEach(function (pokemon) {
        var pool, pokemon_sprite_name, pokemon_sprite_properties;
        pool = this.game_state.groups.pokemon_sprites;
        pokemon_sprite_name = "pokemon_sprite_name_" + pool.countLiving() + pool.countDead();
        pokemon_sprite_properties = Object.create(this.DEFAULT_POKEMON_SPRITE_PROPERTIES);
        pokemon_sprite_properties.texture = pokemon.texture;
        pokemon_sprite_properties.text_properties.text = pokemon.species;
        
        pokemon_sprite = Pokemon.create_prefab_from_pool(pool, Pokemon.PokemonSprite.prototype.constructor, this.game_state, pokemon_sprite_name, pokemon_sprite_position, pokemon_sprite_properties);
        pokemon_sprite_position.x += pokemon_sprite.width + 50;
        if (pokemon_sprite_position.x > (this.width - 50)) {
            pokemon_sprite_position.x = this.initial_pokemon_sprite_position.x;
            pokemon_sprite_position.y += pokemon_sprite.height + 50;
        }
    }, this);
};

The “hide” method, by its turn, will simply make the Pokedex invisible, disable its input events and kill all created PokemonSprites.

Pokemon.Pokedex.prototype.hide = function () {
    "use strict";
    this.visible = false;
    this.inputEnabled = false;
    
    this.game_state.groups.pokemon_sprites.forEach(function (pokemon_sprite) {
        pokemon_sprite.kill();
    }, this);
};

There are two things left to do. First, we need to add all caught Pokemon to the “caught_pokemon” array. The second thing is adding a button to show the Pokedex.

In order to add caught Pokemon to the “caught_pokemon” array we need to change the Pokemon prefab. Once a Pokemon is caught we check if it is the first time this species was caught. If so, we add it to the array. The “already_caught” method simply checks if there is already a Pokemon with the same species in the array.

Pokemon.Pokemon.prototype.catch = function () {
    "use strict";
    var catch_message;
    // kill the Pokemon and show the catch message box
    this.kill();
    
    if (!this.already_caught()) {    
        this.game_state.game.caught_pokemon.push({species: this.species, texture: this.texture_key});
    }
    
    catch_message = new Pokemon.MessageBox(this.game_state, "catch_message", {x: this.game_state.game.world.centerX, y: this.game_state.game.world.centerY}, this.MESSAGE_PROPERTIES);
    catch_message.message_text.text = "Gotcha!";
};

Pokemon.Pokemon.prototype.already_caught = function () {
    "use strict";
    var caught = false;
    this.game_state.game.caught_pokemon.forEach(function (pokemon) {
        if (pokemon.species === this.species) {
            caught = true;
        }
    }, this);
    return caught;
};

Finally, to create the Pokedex button we are going to create a Button prefab which will simply extend Phaser.Button calling a method from “game_state” (defined in the “callback” property) when clicked. Then, we can add a Button prefab in the Tiled map to call the “show_pokedex” method in WorldState. This method will simply call the “show” method from the pokedex.

var Pokemon = Pokemon || {};

Pokemon.Button = function (game_state, name, position, properties) {
    "use strict";
    Phaser.Button.call(this, game_state.game, position.x, position.y, properties.texture, game_state[properties.callback], game_state);
    
    this.game_state = game_state;
    
    this.name = name;
    
    this.game_state.groups[properties.group].add(this);
    
    this.anchor.setTo(0.5);
    
    this.game_state.prefabs[name] = this;
};

Pokemon.Button.prototype = Object.create(Phaser.Button.prototype);
Pokemon.Button.prototype.constructor = Pokemon.Button;
Pokemon.WorldState.prototype.show_pokedex = function () {
    "use strict";
    this.prefabs.pokedex.show();
};

Now you can try catching some Pokemon and check if your Pokedex is being updated. Try catching the same species more than once and see if the Pokedex is only showing each species once.

pokedex

And that concludes this tutorial. In the next one we are going to add Pokestops to get Pokeballs, as well as different types of Pokeballs with different catching rates.

]]>
Make a Mario-Style Platformer with the Phaser Editor https://gamedevacademy.org/make-a-mario-style-platformer-with-the-phaser-editor/ Wed, 28 Sep 2016 00:17:20 +0000 https://gamedevacademy.org/?p=4137 Read more]]> Links to the Editor tool in this tutorial are affiliate link which help Zenva fund the creation of new courses and tutorials

In this tutorial, we create a simple platformer demo with Phaser Editor (an IDE made especially 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 into sections and every section has a link to the source code used in it, this allows you to mess with the code of a section but start with a ready project on the next section.

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 acknowledgment about Phaser states and Arcade physics. Check some resources to learn Phaser:

 

UPDATED November 21, 2017.

Compatible with Phaser Editor v1.4.3 and Phaser v2.6.2

Table of contents

Create the project

First thing is to create the project of our game. In Phaser Editor there are two ways of creating a project: the Phaser Project wizard and the Phaser Example Project wizard. In this article we are going to use the Phaser Project wizard, the one is recommended to create real games. The Phaser Example Project wizard is better to test/modify Phaser and Phaser Editor examples.

To create the project click on File → New → Phaser Project, set the name of the game and press Finish (in this tutorial we use the default values of the options provided by this wizard, but for larger projects you can click the Next button and set options like the project structure or the language).

Learn more about the first steps

By default, the wizard creates a project with a single state and an empty assets pack:

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 instance is created.
WebContent/assets/pack.json A manifest of the game assets.
WebContent/assets/canvas/Level.canvas An empty Level scene (Phaser State) file.
WebContent/assets/canvas/Level.js The compiled Level scene.
Design/ A folder where you can place resources that are not part of the game, like SVG files or the source images of a textures map.

By default, the Level.canvas file is opened in the scene editor (Canvas Editor).

In Phaser Editor, the scenes are compiled into a readable JavaScript code with high-level Phaser API calls. This generated code can be edited by the user to initialize Phaser systems, create other kinds of objects or add event listeners. If you run the project (Alt+F5) you will see an empty screen with a hello world! message. This message object was added directly to the code, open the Level.js file and you will see it:

Level.prototype.addHelloWorldText = function() {
	this.add.text(100, 100, "hello world!");
};

 

(Import the project Step_01 to see the final result)

Load the assets

(You can start with the project Step_01)

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

 

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/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 the 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 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 210×210 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, so you can load just a subset of the assets in a specific moment. In our demo, we just use one section called level.

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:

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.

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

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 pane, set the key, the url, and save.

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, there is the Phaser doc related to the asset type.

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 maps need the image file and the map file (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. This documentation is extracted from the Phaser source, so it will be always synchronized with the Phaser version supported by the editor.

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 them to get a preview.

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 “handmade” 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 maker.

(Import the project Step_02 to see the final result)

Create the scene

(You can start with the project Step_02)

As we mentioned before, the default project created by Phaser Editor includes a Level scene or Phaser State, that is loaded in the index.html file and added to the game in the Main.js file. This is the only scene we are going to use in this tutorial, if you want to add more scenes or prefabs you can create them in File → New → State File| Sprite Prefab | Group Prefab, and load them by adding script assets to the pack.json file.

Learn more about the scene editor

Let’s add some objects to the scene. First, double-click on the Level.canvas file, to opens the scene in the Canvas Editor. In the Assets navigator, 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.

In the previous illustration it shows the Properties Grid, where you can edit the properties of the selected object, and the Outline window, that shows the hierarchy of the scene’s objects.

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 Preview 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 layout:

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

Let’s add some ground to the scene. From the textures-map tiles drop the frame 14 and drop it in the scene. (By the way, with the middle button you can zoom in/out and scroll the scene).

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 types 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 Sprite → Morph To → Tile Sprite.

It converts the simple sprite into a tile sprite (like in game.add.tileSprite). Note in the Properties Grid you can edit the Tile Sprite properties:

To resize the sprite you can change the width and height properties, or you can resize it visually. Right-click on the object and select Sprite → Convert To/Resize Tile Sprite (or just press the L key, actually, you can use this shortcut to morph an object into a tile at the same time you resize it).

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

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

To make the objects to match one with the others, you can enable the snapping mode and set the right step size. Select a ground tile and press W, that is the shortcut to the Enable Snapping (Selection Size) command. You can change the step size manually in the Configurations tab of the editor, in the Editor → Snapping section. To turn the snapping ON and OFF you can press the E key.

Is time to run the game and see what we made. To run the project press the Ctrl+Alt+F5 shortcut. That command starts a local web server and launches the default browser with the game URL as argument:

Learn more about how to run the games

There are some details that need to be explained. First, a magic “hello world!” message appears in the game, the background is white and the dimensions are not the same of the frame shown in the scene editor:

The “hello world!” message was generated by the project wizard, but not as a scene object else as Phaser code. Press Ctrl+Shift+U to open the User Code dialog and remove the code in the Create tab:

The background of the scene in the editor is not the same of the background of the game. This is an intentional decision, to help the user to create the scene with a more creation-friendly background. To change the background of the game go to the Configurations tab, State → Stage section and change the backgroundColor property. For example set it to blue blue:

In the Editor node, in the Scene section, set the width and height to 800×600, that is the game resolution set to the game. Note there is an Editor and State settings. The Editor is related only to the scene editor, to the design-time, and does not affect the game. The State settings are related to the game, those are Phaser properties. We split both settings for convenience.

Now run the game Ctrl+Alt+F5 again and check the changes.

But better than a solid color is to add a background to the game. Drag the BG image from the Asset view and drop it on the scene. The image will get all the space and hide the other objects, to send it to the background select it and press PageDown. Make sure the player is in the front of all the objects, so select it and press PageUp. The scene should look like following. Run the game (or refresh the browser) to see the changes.

(Import the project Step_03 to see the final result)

Add the physics

(You can start with the project Step_03 )

What we want is to make the player (Dino) 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 or Box2D, you can, but the editor is not going to bring special features around it -it will do, eventually-.

To enable the player physics, right-click on it and select Sprite → 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.

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 properties tool-tips with the Phaser doc.

Remember always to save all the changes in the scene, to re-generate the code. In addition to the objects set-up, you need to do some global physics initialization in your Level state.  But wait, is not the code generated each time we modified the scene? Yes, but look there are parts of the code that are preserved from generation to generation. Note at the end of the file there is a text:

/** --- end generated code --- */

All the code written below that line will be preserved by the scene compiler. At the same time, you can insert code between the generated methods via configuration. As we saw before, there is the User Code dialog where you can write your own code at the start or end of each method. If you like to do some initialization before the objects are added to the scene, you can add code to the Before section of the Create method.

So, let’s initialize the physics. Press Ctrl+Shift+U in the scene, in the Create tab, write this.initScene();  on the Before text box:

The initScene method is not defined yet, we have to write it. Save the scene and open the Level.js file. At the end of the file add the initScene method:

Level.prototype.initScene = function () {
    // start the Arcade system
    this.game.physics.startSystem(Phaser.Physics.ARCADE);
 
    // set the global gravity
    this.game.physics.arcade.gravity.y = 800;
};

Note there is an addHelloWorldText method at the end of the file, you can delete it, it was generated by the project wizard and is not used in this game.

Save and refresh the game in the browser, you will see how the Dino player 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.

To create the collision layer, right-click on 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.

Learn more about the Group properties included in the Property Grid

To set the physics properties to the objects in the layer, we use the setAll parameter of the group. Really, setAll is a method of the Phaser.Group class, used to modify the properties of all the children. In the Property Grid it is shown as a property and you can list all the properties and values you want to update.

So let’s click on the setAll property, in the Property Grid, and add these values:

Learn more about the Set All property

Set true the body.immovable property, to make the object not movable by collisions. Set false the body.allowGravity property, to make the object static. Set false the renderable property to hide the object but keep the physics properties.

Now we need to make the player to collides with the collision layer. By the way, you should make public the player and the collision layer, it indicates to the compiler to generate a fPlayer and fCollisionLayer field that can be used outside the create method.

Learn more about design-time/editor object properties

To make the player to collide with the collision layer, add an update method at the end of the Level.js file with this code:

Level.prototype.update = function () {
    this.physics.arcade.collide(this.fPlayer, this.fCollisionLayer);
};

And now run the game (Ctrl+Alt+F5), the Dino should stay on the platform.

(Import the project Step_04 to see the final result)

Add the player controls

(You can start with the project Step_04)

In Phaser, it is very easy to add movements controls. In the initScene method created before, add this code at the end of the method:

// create the cursors
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() {
    this.physics.arcade.collide(this.fPlayer, this.fCollisionLayer);
    
    if (this.cursors.left.isDown) {
        // move to the left
        this.fPlayer.body.velocity.x = -200;
    } else if (this.cursors.right.isDown) {
        // move to the right
        this.fPlayer.body.velocity.x = 200;
    } else {
        // dont move in the horizontal
        this.fPlayer.body.velocity.x = 0;
    }

    // a flag to know if the player is (down) touching the platforms
    var touching = this.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.fPlayer.body.velocity.y = -600;
    }
};

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

(Import the project Step_05 to see the final result)

Add the player animations

(You can start with the project Step_05)

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.

Create three animations, walk, jump, and idle. The walk animation has the frames 8, 9, 10, 11, and it loops at a rate of 6 FPS. The jump has the frames 4, 5, and loops at a rate of 6 FPS. And the idle animation has the frames 0, 1, 2 and loops at a rate of 4 FPS.

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.fPlayer.body.velocity.x == 0) {
        // if it is not moving horizontally play the idle
        this.fPlayer.play("idle");
    } else {
        // if it is moving play the walk
        this.fPlayer.play("walk");
    }
} else {
    // it is not touching the platforms so it means it is jumping.
    this.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_06 to see the final result)

Add coins

(You can start with the project Step_06)

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

Select all 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, and in the setAll property set body.allowGravity to false. Save, a new fFruits var will be generated.

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.fPlayer, this.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, at the end of the file:

/**
 * @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 from the game. Note 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_07 to see the final result)

Conclusions

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

We encourage you to check the Phaser Editor templates provided in the Phaser Example Project wizard, there you will find multi-level and prefabs based demos. In the next tutorial, we are going to introduce these concepts.

Art assets used in this article

 

]]>
How to Create a Pokemon GO Game – Part 1 https://gamedevacademy.org/how-to-create-a-pokemon-go-game-phaser-part-1/ Tue, 06 Sep 2016 22:05:48 +0000 https://gamedevacademy.org/?p=4033 Read more]]> In this tutorial series, we will create a game similar to the popular Pokemon GO. First, we will create a Phaser state to catch Pokemon. Then, we will add a world state where the player can navigate in order to find Pokemon. We are also going to add features of the Pokemon GO game such as: different Pokemon, different pokeballs, pokestops to get pokeballs. In the end we are going to save the player pokedex in an online database.

In this first tutorial I will cover the following content:

  • Creating a catch state where the player can catch Pokemon
  • Using Phaser P2 physics engine for throwing pokeballs and catching Pokemon
  • Creating message boxes that interact with the player to call methods from the game state
  • Creating a world state, which reads a Tiled map with the current Pokemon

To read this tutorial, it is important that you are familiar with the following concepts:

  • Javascript and object-oriented concepts.
  • Basic Phaser concepts, such as: states, sprites, groups and arcade physics
  • Creating maps using Tiled

Learn Phaser by building 15 games

If you want to master Phaser and learn how to publish Phaser games as native games for iOS and Android feel free to check Zenva‘s online course The Complete Mobile Game Development Course – Build 15 Games.

Source code files

You can download the tutorial source code files here.

Level file and game states

In this tutorial we are going to use JSON files like the one below in order to load assets, create groups and prefabs in our game.

{
    "assets": {
        "background_image": {"type": "image", "source": "assets/images/background.png"},
        "message_box_image": {"type": "image", "source": "assets/images/message_box.png"},
        "pokeball_image": {"type": "image", "source": "assets/images/pokeball.png"},
        "pokemon_spritesheet": {"type": "spritesheet", "source": "assets/images/pokemon.png", "frame_width": 98, "frame_height": 85}
    },
    "groups": [
        "background",
        "pokemons",
        "pokeballs",
        "hud"
    ],
    "collision_groups": [
        "pokemons",
        "pokeballs"
    ],
    "prefabs": {
        "background": {
            "type": "background",
            "position": {"x": 0, "y": 0},
            "properties": {
                "texture": "background_image",
                "group": "background"
            }
        },
        "pokeball": {
            "type": "pokeball",
            "position": {"x": 0.5, "y": 0.8},
            "properties": {
                "texture": "pokeball_image",
                "group": "pokeballs",
                "anchor": {"x": 0.5, "y": 0.5},
                "pokeball_speed": 300,
                "catching_rate": 0.3
            }
        },
        "pokemon": {
            "type": "pokemon",
            "position": {"x": 0.5, "y": 0.6},
            "properties": {
                "texture": "pokemon_spritesheet",
                "group": "pokemons",
                "anchor": {"x": 0.5, "y": 0.5},
                "frame": 1,
                "fleeing_rate": 1.0
            }
        }
    }
}

The Phaser states we are going to use are:

  • BootState: responsible for loading the level file
  • LoadingState: responsible for loading all level assets
  • CatchState: represents the screen where the player can catch a Pokemon
  • WorldState: represents the world where the player can navigate in order to find Pokemon. In this first tutorial WorldState will simply show the current Pokemon to catch.

BootState and LoadingState are the simpler ones, and their codes are shown below. As mentioned earlier, BootState simply loads a level file, and send its content as a parameter to LoadingState.

var Pokemon = Pokemon || {};

Pokemon.BootState = function () {
    "use strict";
    Phaser.State.call(this);
};

Pokemon.BootState.prototype = Object.create(Phaser.State.prototype);
Pokemon.BootState.prototype.constructor = Pokemon.BootState;

Pokemon.BootState.prototype.init = function (level_file, next_state) {
    "use strict";
    this.level_file = level_file;
    this.next_state = next_state;
};

Pokemon.BootState.prototype.preload = function () {
    "use strict";
    // load the level file
    this.load.text("level1", this.level_file);
};

Pokemon.BootState.prototype.create = function () {
    "use strict";
    var level_text, level_data;
    // parse the level file as a JSON object and send its data to LoadingState
    level_text = this.game.cache.getText("level1");
    level_data = JSON.parse(level_text);
    this.game.state.start("LoadingState", true, false, level_data, this.next_state);
};

LoadingState, by its turn, iterates through all assets in the level data loading the correct asset for each one. Notice that we use a property called type in order to identify the correct asset to load, and an asset key to save it.

var Pokemon = Pokemon || {};

Pokemon.LoadingState = function () {
    "use strict";
    Phaser.State.call(this);
};

Pokemon.LoadingState.prototype = Object.create(Phaser.State.prototype);
Pokemon.LoadingState.prototype.constructor = Pokemon.LoadingState;

Pokemon.LoadingState.prototype.init = function (level_data, next_state) {
    "use strict";
    this.level_data = level_data;
    this.next_state = next_state;
};

Pokemon.LoadingState.prototype.preload = function () {
    "use strict";
    var assets, asset_loader, asset_key, asset;
    assets = this.level_data.assets;
    for (asset_key in assets) { // load assets according to asset key
        if (assets.hasOwnProperty(asset_key)) {
            asset = assets[asset_key];
            switch (asset.type) {
            case "image":
                this.load.image(asset_key, asset.source);
                break;
            case "spritesheet":
                this.load.spritesheet(asset_key, asset.source, asset.frame_width, asset.frame_height, asset.frames, asset.margin, asset.spacing);
                break;
            case "tilemap":
                this.load.tilemap(asset_key, asset.source, null, Phaser.Tilemap.TILED_JSON);
                break;
            }
        }
    }
};

Pokemon.LoadingState.prototype.create = function () {
    "use strict";
    this.game.state.start(this.next_state, true, false, this.level_data);
};

CatchState code is shown below. First, in the “init” method we need to start the Physics engine. Notice that in this tutorial series we are going to use P2 Physics in order to have rounded collision shapes.

The “create” method from CatchState is responsible for creating groups, collision groups (for the physics engine) and the prefabs. Groups and collision groups can be easily created by iterating through their respective arrays and creating them on Phaser or P2. In order to create the prefabs we are going to iterate through all prefabs described in the JSON file and call a “create_prefab” method.

var Pokemon = Pokemon || {};

Pokemon.CatchState = function () {
    "use strict";
    Phaser.State.call(this);
    
    this.prefab_classes = {
        "background": Pokemon.Prefab.prototype.constructor,
        "pokeball": Pokemon.Pokeball.prototype.constructor,
        "pokemon": Pokemon.Pokemon.prototype.constructor
    };
};

Pokemon.CatchState.prototype = Object.create(Phaser.State.prototype);
Pokemon.CatchState.prototype.constructor = Pokemon.CatchState;

Pokemon.CatchState.prototype.init = function (level_data) {
    "use strict";
    this.level_data = level_data;
    
    this.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
    this.scale.pageAlignHorizontally = true;
    this.scale.pageAlignVertically = true;
    
    // start physics system
    this.game.physics.startSystem(Phaser.Physics.P2JS);
    this.game.physics.arcade.gravity.y = 0;
};

Pokemon.CatchState.prototype.create = function () {
    "use strict";
    var group_name, prefab_name;
    
    // create groups
    this.groups = {};
    this.level_data.groups.forEach(function (group_name) {
        this.groups[group_name] = this.game.add.group();
    }, this);
    
    this.collision_groups = {};
    this.level_data.collision_groups.forEach(function (collision_group_name) {
        this.collision_groups[collision_group_name] = this.game.physics.p2.createCollisionGroup();
    }, this);
    
    // create prefabs
    this.prefabs = {};
    for (prefab_name in this.level_data.prefabs) {
        if (this.level_data.prefabs.hasOwnProperty(prefab_name)) {
            // create prefab
            this.create_prefab(prefab_name, this.level_data.prefabs[prefab_name]);
        }
    }
};

Pokemon.CatchState.prototype.create_prefab = function (prefab_name, prefab_data) {
    "use strict";
    var prefab_position, prefab;
    // create object according to its type
    if (this.prefab_classes.hasOwnProperty(prefab_data.type)) {
        if (prefab_data.position.x > 0 && prefab_data.position.x <= 1) {
            // position as percentage
            prefab_position = new Phaser.Point(prefab_data.position.x * this.game.world.width,
                                              prefab_data.position.y * this.game.world.height);
        } else {
            // position as absolute number
            prefab_position = prefab_data.position;
        }
        prefab = new this.prefab_classes[prefab_data.type](this, prefab_name, prefab_position, prefab_data.properties);
    }
    return prefab;
};

Pokemon.CatchState.prototype.return_to_world = function () {
    "use strict";
    this.game.state.start("BootState", true, false, "assets/levels/world_level.json", "WorldState");
};

The “create_prefab” method starts by calculating the prefab position. This can be an absolute or percentage position. If the position is defined as number between zero and one (e.g: 0.5), its position will be calculated as a percentage of the world dimensions. Otherwise it will simply be the position defined in the JSON file. After defining the prefab position, we create it by calling the appropriate constructor with any custom properties declared in the JSON level file. Notice that we do that by saving the prefab constructors in a “prefab_classes” property, indexed by the prefab type. This is possible because all prefabs have the same constructor, defined in a generic Prefab class (shown below) which all Prefabs must extend.

var Pokemon = Pokemon || {};

Pokemon.Prefab = function (game_state, name, position, properties) {
    "use strict";
    Phaser.Sprite.call(this, game_state.game, position.x, position.y, properties.texture);
    
    this.game_state = game_state;
    
    this.name = name;
    
    this.game_state.groups[properties.group].add(this);
    this.frame = +properties.frame;
    if (properties.anchor) {
        this.anchor.setTo(properties.anchor.x, properties.anchor.y);
    }
    
    this.game_state.prefabs[name] = this;
};

Pokemon.Prefab.prototype = Object.create(Phaser.Sprite.prototype);
Pokemon.Prefab.prototype.constructor = Pokemon.Prefab;

Now let’s create our last state for this tutorial: WorldState. This state loads a Tiled map like the one shown below. Since the focus of this tutorial is not on Tiled, you’re free to use the same map provided in the source code, or create your own map. The only things you must be careful is that the objects in the map must have at least their group and texture defined in their properties.

map

Besides the Tiled map, WorldState will also going to use a JSON level file to load the assets, the map and create the groups, like the one shown below:

{
    "assets": {
        "map_tileset": {"type": "image", "source": "assets/images/open_tileset.png"},
        "pokemon_spritesheet": {"type": "spritesheet", "source": "assets/images/pokemon.png", "frame_width": 98, "frame_height": 85},
        
        "world_tilemap": {"type": "tilemap", "source": "assets/maps/world.json"}
    },
    "groups": [
        "spawns"
    ],
    "map": {
        "key": "world_tilemap",
        "tilesets": ["map_tileset"]
    }
}

This is the code for WorldState. Similarly to CatchState it starts P2 physics engine in the “init” method. However, it also has to create the tilemap, using the data provided by the JSON level file. Then, in the “create” method it creates the map layers, game groups and prefabs. The map layers and groups are created similarly to what we’ve done in CatchState, but in order to create prefabs we have to iterate through the object layers in the Tiled map and call a “create_object” method for each object.

var Pokemon = Pokemon || {};

Pokemon.WorldState = function () {
    "use strict";
    Phaser.State.call(this);
    
    this.prefab_classes = {
        "pokemon_spawn": Pokemon.PokemonSpawn.prototype.constructor
    };
};

Pokemon.WorldState.prototype = Object.create(Phaser.State.prototype);
Pokemon.WorldState.prototype.constructor = Pokemon.WorldState;

Pokemon.WorldState.prototype.init = function (level_data) {
    "use strict";
    var tileset_index;
    this.level_data = level_data;
    
    this.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
    this.scale.pageAlignHorizontally = true;
    this.scale.pageAlignVertically = true;
    
    // start physics system
    this.game.physics.startSystem(Phaser.Physics.P2JS);
    this.game.physics.arcade.gravity.y = 0;
    
    // create map and set tileset
    this.map = this.game.add.tilemap(level_data.map.key);
    tileset_index = 0;
    this.map.tilesets.forEach(function (tileset) {
        this.map.addTilesetImage(tileset.name, level_data.map.tilesets[tileset_index]);
        tileset_index += 1;
    }, this);
};

Pokemon.WorldState.prototype.create = function () {
    "use strict";
    var group_name, object_layer, collision_tiles;
    
    // create map layers
    this.layers = {};
    this.map.layers.forEach(function (layer) {
        this.layers[layer.name] = this.map.createLayer(layer.name);
    }, this);
    // resize the world to be the size of the current layer
    this.layers[this.map.layer.name].resizeWorld();
    
    // create groups
    this.groups = {};
    this.level_data.groups.forEach(function (group_name) {
        this.groups[group_name] = this.game.add.group();
    }, this);
    
    this.prefabs = {};
    
    for (object_layer in this.map.objects) {
        if (this.map.objects.hasOwnProperty(object_layer)) {
            // create layer objects
            this.map.objects[object_layer].forEach(this.create_object, this);
        }
    }
};

Pokemon.WorldState.prototype.create_object = function (object) {
    "use strict";
    var object_y, position, prefab;
    // tiled coordinates starts in the bottom left corner
    object_y = (object.gid) ? object.y - (this.map.tileHeight / 2) : object.y + (object.height / 2);
    position = {"x": object.x + (this.map.tileHeight / 2), "y": object_y};
    // create object according to its type
    if (this.prefab_classes.hasOwnProperty(object.type)) {
        prefab = new this.prefab_classes[object.type](this, object.name, position, object.properties);
    }
    this.prefabs[object.name] = prefab;
};

The “create_object” method starts by calculating the prefab position because we want the anchor point of the sprites to be their centers, while Tiled use it as the bottom left corner of the object. Then, we instantiate the correct prefab using the “prefab_classes” property exactly the same way we did in CatchState.

By now, you can try starting both CatchState and WorldState to see if they are correctly creating the Prefabs. In order to do that you have to add all prefabs in the “prefab_classes” property, even if they’re not doing anything yet. You should see the following screens:

worldcatch

PokemonSpawn prefab

We are going to start by creating the PokemonSpawn prefab, which will show a Pokemon in the world, and allow the player to catch it. This prefab will be used in WorldState, so be sure to change your code to start with WorldState in order to test it.

The code for PokemonSpawn is shown below. In the constructor we need to appropriately set the anchor point and scale. Then, we enable input for it, as well as add an onInputDown event. This event will call the “try_catching” method, which will simply start CatchState.

var Pokemon = Pokemon || {};

Pokemon.PokemonSpawn = function (game_state, name, position, properties) {
    "use strict";
    Pokemon.Prefab.call(this, game_state, name, position, properties);
    
    this.anchor.setTo(0.5);
    this.scale.setTo(0.5);
    
    // add input event to try catching this Pokemon
    this.inputEnabled = true;
    this.events.onInputDown.add(this.try_catching, this);
};

Pokemon.PokemonSpawn.prototype = Object.create(Pokemon.Prefab.prototype);
Pokemon.PokemonSpawn.prototype.constructor = Pokemon.PokemonSpawn;

Pokemon.PokemonSpawn.prototype.try_catching = function () {
    "use strict";
    // start CatchState
    this.game_state.game.state.start("BootState", true, false, "assets/levels/catch_level.json", "CatchState");
};

By now, you can try clicking on the Pokemon in WorldState and check if it properly starts CatchState.

Pokemon and Pokeball prefabs

Now we are going to create the prefabs for the Pokemon and the Pokeball, since those two prefabs will work together in order to allow the player to catch Pokemon.

First, let’s create the Pokemon constructor as below. The constructor will simply save the Pokemon fleeing rate from is properties (defined in the JSON file), and will start its physical body. For the physical body we need to define it as static, since we don’t want it to move, define its collision body as a circle, set its collision group and tell the engine which groups collides with it (the pokeballs group, in our case).

var Pokemon = Pokemon || {};

Pokemon.Pokemon = function (game_state, name, position, properties) {
    "use strict";
    Pokemon.Prefab.call(this, game_state, name, position, properties);
    
    this.BODY_RADIUS = 30;
    
    this.fleeing_rate = properties.fleeing_rate;
    
    // initialize Pokemon physical body
    this.game_state.game.physics.p2.enable(this);
    this.body.static = true;
    this.body.setCircle(this.BODY_RADIUS);
    this.body.setCollisionGroup(this.game_state.collision_groups.pokemons);
    this.body.collides([this.game_state.collision_groups.pokeballs]);
};

Pokemon.Pokemon.prototype = Object.create(Pokemon.Prefab.prototype);
Pokemon.Pokemon.prototype.constructor = Pokemon.Pokemon;

Now that we have our collidable Pokemon, let’s go to the Pokeball prefab. In the constructor (shown below) we need to save some properties that will be used later and create input events. We will use two input events:

  1. when the player clicks on the pokeball it will start dragging it
  2. when the player releases the pokeball it should throw it
var Pokemon = Pokemon || {};

Pokemon.Pokeball = function (game_state, name, position, properties) {
    "use strict";
    var rotate_tween;
    Pokemon.Prefab.call(this, game_state, name, position, properties);
    
    this.TWEEN_DURATION = 0.5;
    this.THROW_THRESHOLD = 50;
    
    this.pokeball_speed = properties.pokeball_speed;
    this.catching_rate = properties.catching_rate;
    
    this.dragging = false;
    
    this.initial_position = {x: this.x, y: this.y};
    
    // add input events to drag and throw the pokeball
    this.inputEnabled = true;
    this.events.onInputDown.add(this.drag, this);
    this.events.onInputUp.add(this.throw, this);
};

Pokemon.Pokeball.prototype = Object.create(Pokemon.Prefab.prototype);
Pokemon.Pokeball.prototype.constructor = Pokemon.Pokeball;

So, let’s implement the methods for those two input events. First, the “drag” method will simply set the “dragging” property to true. Then, we need to change the “update” method to change the pokeball position to be the same as the active pointer if it is being dragged.

Pokemon.Pokeball.prototype.drag = function () {
    "use strict";
    this.dragging = true;
};

Pokemon.Pokeball.prototype.update = function () {
    "use strict";
    // if the pokeball is being dragged, update its position to follow the active pointer
    if (this.dragging) {
        this.x = this.game_state.game.input.activePointer.x;
        this.y = this.game_state.game.input.activePointer.y;
    }
};

The “throw” method, by its turn, will start by setting the “dragging” property to false. Then, it calculates the distance that the pokeball was dragged, from its distance to the initial position. If it was dragged above a pre-defined threshold, then we should throw the pokeball by initializing its physical body and changing its velocity on both x and y directions.

Pokemon.Pokeball.prototype.throw = function () {
    "use strict";
    var distance_to_initial_position;
    
    // stop draggin the pokeball
    this.dragging = false;
    
    // throw the pokeball if the distance to the initial position is above the threshold
    distance_to_initial_position = new Phaser.Point(this.x - this.initial_position.x, this.y - this.initial_position.y);
    if (distance_to_initial_position.getMagnitude() > this.THROW_THRESHOLD) {
        distance_to_initial_position.normalize();
        // initialize the pokeball physical body
        this.init_body();
        this.body.velocity.x = -distance_to_initial_position.x * this.pokeball_speed;
        this.body.velocity.y = -distance_to_initial_position.y * this.pokeball_speed;
    } else {
        this.reset(this.initial_position.x, this.initial_position.y);
    }
};

Now let’s implement the “init_body” method. The pokeball physical body will be similar to the Pokemon one, except that it won’t be static and we are going to add a callback (“start_catching”) to when it collides with a Pokemon.

Pokemon.Pokeball.prototype.init_body = function () {
    "use strict";
    this.game_state.game.physics.p2.enable(this);
    this.body.setCircle(this.width / 2);
    this.body.setCollisionGroup(this.game_state.collision_groups.pokeballs);
    this.body.collides([this.game_state.collision_groups.pokemons]);
    // start catching a Pokemon when the pokeball collides with it
    this.body.onBeginContact.add(this.start_catching, this);
};

The “start_catching” method starts by destroying the physical body, since we don’t need it anymore and will make the Pokemon invisible. Then, it will play a rotate tween animation to simulate the catching process. When the tween animation is done it will call a “try_catching” method, which will check if the Pokemon was succesfully caught.

The “try_catching” method will generate a random number between 0 and 1 and compare it with the pokeball catching rate. If the generated number is lower than the catching rate the Pokemon was succesfully caught, and we need to kill the pokeball. Otherwise, we still need to check if the Pokemon will flee. If so, we also need to kill the pokeball and return to WorldState, so that the player can not throw it anymore. Otherwise, we just make the pokemon visible again and reset the pokeball to its initial position.

Pokemon.Pokeball.prototype.start_catching = function (body_b) {
    "use strict";
    var pokemon, pokemon_position, rotate_tween;
    this.body.destroy();
    
    pokemon = body_b.sprite;
    pokemon.visible = false;
    
    // play a rotate animation to simulate the catching process
    rotate_tween = this.game_state.game.add.tween(this);
    rotate_tween.to({angle: "-45"}, Phaser.Timer.SECOND * this.TWEEN_DURATION);
    rotate_tween.to({angle: "+90"}, Phaser.Timer.SECOND * this.TWEEN_DURATION * 2);
    rotate_tween.to({angle: "-45"}, Phaser.Timer.SECOND * this.TWEEN_DURATION);
    rotate_tween.onComplete.add(this.try_catching.bind(this, pokemon), this);
    rotate_tween.start();
};

Pokemon.Pokeball.prototype.try_catching = function (pokemon) {
    "use strict";
    var random_number;
    // check if the pokemon was caught
    random_number = this.game_state.rnd.frac();
    if (random_number < this.catching_rate) {
        pokemon.catch();
        this.kill();
    } else {
        // check if the pokemon has fled
        if (!pokemon.fled()) {
            pokemon.visible = true;
            this.reset(this.initial_position.x, this.initial_position.y);
        } else {
            this.kill();
            this.game_state.return_to_world();
        }
    }
};

Now we need to implement the “catch” and “fled” methods in the Pokemon prefab.

The first method will simply kill the Pokemon and print a message in the console and go back to WorldState. The second method will start by generating a random number between 0 and 1. If this number is lower than the Pokemon fleeing rate, then it successfuly fled. Then, we will simply print a message in the console if the Pokemon has fled and will return is result in the end of the method.

Pokemon.Pokemon.prototype.catch = function () {
    "use strict";
    // kill the Pokemon and show the catch message box
    this.kill();
    console.log("Gotcha!");
    this.game_state.return_to_world();
};

Pokemon.Pokemon.prototype.fled = function () {
    "use strict";
    var flee_chance, fled;
    // check if the Pokemon will flee
    flee_chance = this.game_state.rnd.frac();
    fled = flee_chance < this.fleeing_rate;
    if (fled) {
        // kill the Pokemon and show the fled message box
        this.kill();
        console.log("You lost it!");
    }
    return fled;
};

Finally, we only need to implement the “return_to_world” method in CatchState. This method will simply start WorldState with the world JSON file.

Pokemon.CatchState.prototype.return_to_world = function () {
    "use strict";
    this.game.state.start("BootState", true, false, "assets/levels/world_level.json", "WorldState");
};

By now you can already try catching a Pokemon. Try changing the catch and fleeing rates in order to test different outcomes.

catching

MessageBox prefab

In the end of this tutorial we are going to show message boxes when a Pokemon is caught or when it flees. Those message boxes will have input events to call methods from the game state.

Let’s start by creating the MessageBox prefab. This prefab will simply create a TextPrefab to show its message and add an input event. The input event will call a method from the game state defined in the “callback” property from the properties parameter.

var Pokemon = Pokemon || {};

Pokemon.MessageBox = function (game_state, name, position, properties) {
    "use strict";
    Pokemon.Prefab.call(this, game_state, name, position, properties);
    
    // create TextPrefab to show the message
    this.message_text = new Pokemon.TextPrefab(this.game_state, this.name + "_text", Object.create(this.position), properties.text_properties);
    this.message_text.anchor.setTo(0.5);
    
    // add input event to call game state method
    this.inputEnabled = true;
    this.events.onInputDown.add(this.game_state[properties.callback], this.game_state);
};

Pokemon.MessageBox.prototype = Object.create(Pokemon.Prefab.prototype);
Pokemon.MessageBox.prototype.constructor = Pokemon.MessageBox;

Now let’s change the Pokemon prefab to show the message boxes when the Pokemon is caught or when it flees.

First, we are going to add a “MESSAGE_PROPERTIES” property in the Pokemon prefab constructor, which will be used to create the message boxes. Notice that the callback for the message boxes will be the “return_to_world” method in game state. Then, we can change the “catch” method to, instead of printing a message in the console, it will show a message box. Next we are going to change the “fled” method to also create a message box instead of printing a message in the console.

var Pokemon = Pokemon || {};

Pokemon.Pokemon = function (game_state, name, position, properties) {
    "use strict";
    Pokemon.Prefab.call(this, game_state, name, position, properties);
    
    this.BODY_RADIUS = 30;
    this.MESSAGE_PROPERTIES = {
        texture: "message_box_image",
        group: "hud",
        anchor: {x: 0.5, y: 0.5},
        callback: "return_to_world",
        text_properties: {
            text: "",
            group: "hud",
            style: {
                font: "32px Arial",
                fill: "#000"
            }
        }
    };
    
    this.fleeing_rate = properties.fleeing_rate;
    
    // initialize Pokemon physical body
    this.game_state.game.physics.p2.enable(this);
    this.body.static = true;
    this.body.setCircle(this.BODY_RADIUS);
    this.body.setCollisionGroup(this.game_state.collision_groups.pokemons);
    this.body.collides([this.game_state.collision_groups.pokeballs]);
};

Pokemon.Pokemon.prototype = Object.create(Pokemon.Prefab.prototype);
Pokemon.Pokemon.prototype.constructor = Pokemon.Pokemon;

Pokemon.Pokemon.prototype.catch = function () {
    "use strict";
    var catch_message;
    // kill the Pokemon and show the catch message box
    this.kill();
    catch_message = new Pokemon.MessageBox(this.game_state, "catch_message", {x: this.game_state.game.world.centerX, y: this.game_state.game.world.centerY}, this.MESSAGE_PROPERTIES);
    catch_message.message_text.text = "Gotcha!";
};

Pokemon.Pokemon.prototype.fled = function () {
    "use strict";
    var flee_chance, fled, flee_message;
    // check if the Pokemon will flee
    flee_chance = this.game_state.rnd.frac();
    fled = flee_chance < this.fleeing_rate;
    if (fled) {
        // kill the Pokemon and show the fled message box
        this.kill();
        flee_message = new Pokemon.MessageBox(this.game_state, "flee_message", {x: this.game_state.game.world.centerX, y: this.game_state.game.world.centerY}, this.MESSAGE_PROPERTIES);
        flee_message.message_text.text = "You lost it!";
    }
    return fled;
};

Finally, we need to remove the calls to “return_to_world” that we added in the Pokemon and Pokeball prefabs.

By now you can try catching a Pokemon again to see if the message boxes are being correctly displayed, as well as if the callback is being properly called.

gotcha_message lost_message

And we finished the first part of this tutorial series. In the next tutorial we are going to allow the player to navigate the world in order to find Pokemon, which will be randomly spawned. We are also going to add different Pokemon, and a Pokedex menu where the player can see which Pokemon were already caught

]]>