No results found

Try a different or more specific query
Developer Console
Amazon Developer Blogs

Amazon Developer Blogs

Showing posts tagged with Intro

July 22, 2014

Jesse Freeman

Welcome to part two of my Introduction to Phaser. In the first part we configured our dev environment as well as the code we’ll need to run Phaser itself. If you missed the first tutorial, please go back and follow those steps before moving on. In this tutorial we are going to cover the following:

  • Preloading Assets
  • Displaying Images & Sprites
  • Building The Intro Loop
  • How to Start The Game
  • How to End The Game

Let’s get started.

Preloading Assets

Phaser has a built in preloader library. Over the course of this tutorial we will be loading in images, sprite sheets and audio files that will be accessible globally within to our game.

Step 1. If you are building your project locally with NodeJS or Apache you’ll need to copy over all of the assets (click here to download) and put them inside of the deploy folder like so:

You do not need to follow this step if you are using CodePen since the same files are being hosted online.

Step 2. Now let’s add the following to the empty preload function we created in our state object. The code bolded below represents what you need to actually add since we have already defined the preload function itself:

preload: function(){
    this.load.image("wall", "/assets/wall.png");
    this.load.image("background", "/assets/background-texture.png");
}

If you are using CodePen, you will need to preface the urls with http://games.jessefreeman.com/wp-content/public/workshop/phaser/ in order for this to correctly load. As an example, to load in the wall.png you will need the following URL:

http://games.jessefreeman.com/wp-content/public/workshop/phaser/assets/wall.png

Remember to do this for any external asset we preload in our game.

Before we move on, let’s talk about what is happening here. First, you’ll notice that we are calling Phaser’s built in game methods via the this scope. That’s because when our state is loaded up it assumes the same scope as the game object itself. This will allow us to call all of Phaser’s built in methods directly. Next, there are two parts to our load.image call, the unique id of the asset itself and the path to the asset so Phaser knows where to load it from.

Step 3. Now we will need to load in our player sprite sheet. Sprite sheets can be vertical, horizontal or even a grid. The only thing to keep in mind is that each sprite will need to be the exact same width and height in order for this to work correctly. This is what the sprite sheet looks like:

 

To correctly load this into our game we’ll need to add the following code below where we loaded the first two images:

this.load.spritesheet("player", "/assets/player.png", 48, 48);

This is similar to our load.image request except we have to define the width and height of the sprite. This allows Phaser to have the correct dimensions it needs to cut up our sprites into separate frames for animating later on. Phaser also supports loading texture atlases as well if you prefer to package all of your artwork into a single graphic but we will not be covering that in this tutorial.

Step 4. To test that this is working correctly, go back to your browser, refresh the page and inside of network connection debug tool you should now see that all of the game’s assets are loading correctly.

Now that we have our images, let’s look into how we can display them on the screen.

Displaying Images and Sprites

Adding images and sprites to the display is very easy in Phaser. To get started we are going to create our game’s background then make it scroll before adding in the player.

Step 1. Add the following to the create() function

this.background = this.add.tileSprite(0,0, this.world.width, this.world.height, 'background');

Here we are setting up a new background variable and assign it a TileSprite by calling this.add.tileSprite. The method requires x, y, width, height and label values. Since this texture will take up the entire screen, we are just going to set its x and y value to 0,0 and the width and height to the world’s width and height.

Step 2. Add the following constant to the top of our main.js file:

var SPEED = 200;

This SPEED value will now be a global in our game and help keep everything in sync.

Step 3. Now add the following code right below where we defined our background in the create() method:

this.background = this.add.tileSprite(0,0, this.world.width, this.world.height, 'background');
this.background.autoScroll(-SPEED,0);

Step 4. At this point we have enough to see the background scrolling by based on our SPEED constant. Refresh the browser to see the background scroll.

Step 5. Next, add the following constant, which will represent the gravity in our game:

var GRAVITY = 900;

Step 6. Add the following to the top of the create() function to setup the physics engine:

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

Step 7. Now add the following to our create() method below our background texture:

this.player = this.add.sprite(0,0,'player');
this.player.animations.add('fly', [0,1,2], 10, true);
this.physics.arcade.enableBody(this.player);
this.player.body.collideWorldBounds = true;

Here we are creating a sprite instance from the sprite sheet image we previously loaded. Once we set the player sprite up we are going to create our fly animation. We do this by simply calling animations.add on the sprite itself and supply: a label for the animation, the frames, the amount of milliseconds between each frame and if it should loop.

Step 8. Refresh the browser and now you should see the players animate, and it should fall to the bottom of the screen due to gravity:

In most physics engines, a physics body represents the actual object collision area. It’s easy to define a downward pull by adding gravity to the y value of the player’s body object. Also, by setting the player.body.collideWorldBounds to true we tell the physics body that it should be constrained by the boundaries of the game’s world so the player doesn’t fall off the screen.

How To Start The Game

Now that we have a player and our background, let’s get started adding in a way to play our game. As we build this out, we’ll be taking advantage of the single state of our Phaser game so we’ll need to set up variables to represent the game modes to let us know when the it has started and when it is over. In order to do this we’ll need to create a function that will reset all of our games values first.

Step 1. Add the following function to our state object

update: function(){
},
reset:function(){
	this.gameStarted = false;
	this.gameOver = false;
	this.score = 0;
}

It’s important to note that you need to add a trailing comma to the previous function as you continue to add new functions to the game’s state object so we don’t get an error.

Step 2. Let’s add a call to reset()at the end of our create() function like so:

this.reset();

Now we have a convenient way to reset all of our game values at anytime by calling the reset() function. Not only will this help us get the game ready in the create() function but later on in the when we want to restart the game.

Step 3. Now we need to do a few things in order to build out our intro loop. Add the following to our reset() function:

this.player.body.allowGravity = false;
this.player.reset(this.world.width / 4, this.world.centerY);
this.player.animations.play('fly');

Here you can see that we are turning off our player’s gravity, resetting his position and setting the animation to fly.

Step 4. Now that our player in the correct position for the intro loop, let’s move the background.autoScroll() out of our create() function and put it into the reset() function with the following modification to the x value:

reset:function(){
    this.background.autoScroll(-SPEED * .80 ,0);

Here you’ll notice that we are now to multiplying the SPEED constant by .80 which will slow it down a bit and give us a nice little parallax effect when we add in the walls later on in the tutorial.

Step 5. At this point you can refresh the browser to see the player stays in one place and the background is scrolling a little slower:

Step 6. Now we will need to start building in the logic to differentiate between the attract loop and game play.  Let’s add the following to the update() function:

update: function(){
    if(this.gameStarted){

    }else{
        this.player.y = this.world.centerY + (8 * Math.cos(this.time.now/200));
    }
},	

Here we test if the gameStarted value is true, which means the game is running. If it is false we know that we are in the intro loop. During the intro loop we are going to automatically move the player sprite up and down like he is floating until the player starts the game. You can see that we use Math.cos to modify the y position of the player over each frame, which will give us our up and down motion.

Step 7. Refresh the game in the browser and can see the effect.

Displaying Text

At this point we have our intro loop but we don’t have a way to let the player know what they should do next. We’ll create some text that will not only tell the player how to start the game but also will be used to display the score when the game is running.

Step 1. Add the following code below where we setup our player sprite in the create() function:

this.player.body.collideWorldBounds = true;

this.scoreText = this.add.text(
    this.world.centerX,
    this.world.height/5,
    "",
    {
        size: "32px",
        fill: "#FFF",
        align: "center"
    }
);

As you can see, Phaser supports canvas text and also embedded web fonts if you have them loaded up into your page. To keep things simple we’ll just use the default font, which is Arial. Here we are setting the x and y position of the text, passing it an empty string to start with and defining an object for how the text should be styled.

Step 2. Now we’ll need to set some text to be displayed. To do this, we’ll set it up in the restart() function then add the following to it:

this.scoreText.setText("TOUCH TO\nSTART GAME");

You can use \n to create line breaks in your text.

Step 3. Refresh browser and you should now see the text rendering correctly:

While we can now see our start text, you’ll notice that it’s off center. We can use a built-in feature of Phaser that allows us to anchor elements.

Step 4. In our create() function, right after we instantiated our scoreText instance, add the following code:

        align: "center"
    }
);
this.scoreText.anchor.setTo(0.5, 0.5);

This will center the anchor position of the text object which helps give the impression that it is properly align when displayed.

Step 5. Refresh the browser to see the changes

Now that we have our intro loop complete, let’s look into how to start our game.

Starting The Game

In this section we are going to wire up our game to start when the player presses the mouse button and if the game is running, we’ll make our player fly up.

Step 1. We’ll need to create our start function on the state object:

start: function(){
    this.player.body.allowGravity = true;
    this.scoreText.setText("SCORE\n"+this.score);
    this.gameStarted = true;
}

Just like we did before, make sure you remember to insert a comma before you add this function. When called, this will enable the player’s gravity again. Next, we change the display to show the score and set the gameStarted flag to true.

Step 2. Now we need a way of calling the start() function. We’ll be adding a single function that will handle any mouse click. Let’s go ahead and create the jet() function on our state object:

jet: function(){
    if(!this.gameStarted){
        this.start();
    }

    if(!this.gameOver){
        this.player.body.velocity.y = -JET;
    }
}

Here we are testing if the game has not started when the function is called. If the game is in the intro loop mode, meaning that gameStarted is false, we call start() to begin the game. If the game is not over, we also change the velocity of the player’s body. By changing the velocity.y value we immediately send the player flying up. You’ll notice that we are applying a negative value to move up. Now we just need our JET constant.

Step 3. Add a constant for the JET value at the top of our game’s code:

var JET = 420;

Step 4. Now in our create() method, we can bind the mouse click to call our jet() function above where we call this.resent() like so:

this.input.onDown.add(this.jet, this);
this.reset();

Phaser handles the mouse input for us by allowing you to easily bind the onDown event to a function, in this case jet(), and supply a scope for the callback. This last bit is critical for maintaining scope in your game as you bind events. By passing this along with the reference to the jet() function we can safely reference properties in the game state like we have been in other places of our code.

Step 5. Now we are ready to refresh the browser and test out flying up and falling down.

Step 6. At this point we are ready to clean up the player animations. Add the following to the update() function, inside where we test if the game has started. We stop the jet animation when the player is falling and start it back up when the player is moving up:

update: function(){
    if(this.gameStarted){
        if(this.player.body.velocity.y > -20){
            this.player.frame = 3;
        }else{
            this.player.animations.play("fly");
        }

I usually tie all of my animations to the game object’s physics, in this case testing the value of the player’s velocity and updating the animation to reflect that movement. You’ll note that we set the fall frame number manually to display when the jet is off. It’s not critical to create a one-frame animation if you know the correct sprite ID.

Step 7. Refresh the browser to test out the new animations we added to the player:

How To End The Game

We now have everything we need in order to run our game, with the exception of detecting when the game is over.

Step 1. To create the game over logic we are going to need to figure out when the player actually hits the bottom of the screen and goes “out of bounds”. Add the following code just below where we setup our player’s animation in the update() function:

        this.player.animations.play("fly");
    }

    if(!this.gameOver){
        if(this.player.body.bottom >= this.world.bounds.bottom){
            this.setGameOver();
        }
    }
}else{
    this.player.y = (this.world.height/2) + 8 * Math.cos(this.time.now/ 200);

Here you can see we are testing to make sure that the game is not over. This will keep the setGameOver() function from getting called continuously when the player touches the bottom of the screen. Once we verify that the game is not over, we test to make sure the player’s body is above the bottom of the world bounds. Phaser has several shortcuts for getting values from game objects.  Accessing the .bottom property keeps us from having to manually configure the player’s dimensions.

 

Step 2. Now we need to create our setGameOver() function:

setGameOver: function(){
    this.gameOver = true;
    this.scoreText.setText("FINAL SCORE\n"+ this.score+"\n\nTOUCH TO\nTRY AGAIN");
	this.background.autoScroll(0, 0);
}

Here you’ll see that we set the gameOver flag to true, change the text to reflect that the game is over and stop the background from scrolling.

Step 3. At this point we have enough logic to actually test that our game can end. Refresh the browser and let the player fall to the bottom of the screen.

Now we need a way to restart out game.

Step 4. Let’s modify our jet() function where we test if the game is over. Add the following else condition to that logic block like so:

if(!this.gameOver){
    this.player.body.velocity.y = -JET;
}else if(this.time.now > this.timeOver + 400){
    this.reset();
}

You’ll notice that we are testing a new variable called timeOver. The basic idea here is that we are creating a simple delay between the time that the game is over, and when the player can click to restart. At the end of most game sessions, the player is frantically clicking away before they die to try and extend their session.  Without a delay before restart, the player would accidentally restart the game without seeing their final score. To overcome this, we’re going to test that 400 milliseconds have passed before we actually let the player restart the game, giving them just enough time to see their final score.

Step 5. To make this fully work we’ll want to save the timeOver value when the player dies. Add the following to our the end of our setGameOver() function:

this.timeOver = this.time.now;

By saving out the current game’s time.now value we are able to track how many milliseconds go by before we allow the player to reset the game.

Step 6. Refresh browser and give it a try. You should now be able to fully start, end and restart the game.

Conclusion

Our game is starting to come together. We have sprites on the screen, we are able to control the player to make them fly, we have an intro loop, the game, and a “game over” state to manage. Coming up next we will add in our obstacles, add collision detection, score, points and talk about publishing our game.

Phaser Part 3

- Jesse Freeman (@jessefreeman)