Adding Physics
When we last left our hero in part 1 of Creating an endless runner game in Phaser he wasn’t able to do much. Really all he could do is watch the power bar go up and down. Let’s change that now by applying the power of the bar to the hero. We are going to that by adding physics to the game.
The first thing to do is to start the physics engine. There are several engines in Phaser, we will be using the Arcade engine.
At the end of the create function, (but just above the mouseListeners) place this line of code to start the physics engine
//start the physics engine game.physics.startSystem(Phaser.Physics.ARCADE);
This will let phaser know that we want to add physics to our sprites. However, it doesn’t automatically add physics to every single sprite. We must enable each sprite. Place this code on the next line.
//enable the hero for physics game.physics.enable(this.hero, Phaser.Physics.ARCADE);
Now our sprites are ready to have the physics properties set. Let’s make a jump function to set the velocity of our hero.
doJump: function() { this.hero.body.velocity.y = -this.power * 12; }
We only want to the y velocity and we want to set it to a negative number to make it go upwards. I set it to the power(or width of the PowerBar) times 12. This seemed to give the right speed upwards.
This is how the stateMain.js should look now
var StateMain = { preload: function() { game.load.image("ground", "images/ground.png"); game.load.image("hero", "images/hero.png"); game.load.image("bar", "images/powerbar.png"); game.load.image("block", "images/block.png"); }, create: function() { this.power = 0; //turn the background sky blue game.stage.backgroundColor = "#00ffff"; //add the ground var ground = game.add.sprite(0, game.height * .9, "ground"); //add the hero in this.hero = game.add.sprite(game.width * .2, ground.y - 25, "hero"); //add the power bar just above the head of the hero this.powerBar = game.add.sprite(this.hero.x + 25, this.hero.y - 25, "bar"); this.powerBar.width = 0; //start the physics engine game.physics.startSystem(Phaser.Physics.ARCADE); //enable the hero for physics game.physics.enable(this.hero, Phaser.Physics.ARCADE); //set listeners game.input.onUp.add(this.mouseUp, this); game.input.onDown.add(this.mouseDown, this); }, mouseDown: function() { this.timer = game.time.events.loop(Phaser.Timer.SECOND / 1000, this.increasePower, this); }, mouseUp: function() { this.doJump(); game.time.events.remove(this.timer); this.power = 0; this.powerBar.width = 0; }, increasePower: function() { this.power++; this.powerBar.width = this.power; if (this.power > 50) { this.power = 50; } }, doJump: function() { this.hero.body.velocity.y = -this.power * 12; }, update: function() {} }
As you can see when you release the mouse the hero goes up and stays there:
If the example above isn’t working correctly, click here to open in a new tab
What goes up must come down
To make our hero come back down to earth we need to add gravity to his body. We can set a global gravity, but that will affect the ground as well and make the ground fall off the screen. We can override that by setting the ground’s gravity to zero but it just seems easy to just set the hero’s gravity instead. Let’s give him a lot of gravity to make the hero fall quickly.
this.hero.body.gravity.y = 200;
If you run the game now, you’ll see that the hero falls right through the bottom of the game. Also in the example above the hero can fly out the top of the game. We can stop both with this one line of code:
this.hero.body.collideWorldBounds = true;
Now the hero stays in the game, but still, falls through the ground. Let’s fix that.
First, we need to make the ground sprite accessible to the rest of the state.
Change the line
var ground = game.add.sprite(0, game.height * .9, "ground");
TO
this.ground = game.add.sprite(0, game.height * .9, "ground");
This will change the local sprite to a statewide sprite. Important: You’ll also need to change the ground variable to this.ground.
Enable the physics for the ground
game.physics.enable(this.ground, Phaser.Physics.ARCADE);
Next set up a collision relationship in the update function. This will cause the physics to act upon each other when the two objects collide.
update: function() { game.physics.arcade.collide(this.hero, this.ground); }
If you run the game now, you’ll see that the hero pushes the ground off of the screen.
We can fix that by telling Phaser that the ground is immovable.
this.ground.body.immovable = true;
This is how your stateMain.js should look now:
var StateMain = { preload: function() { game.load.image("ground", "images/ground.png"); game.load.image("hero", "images/hero.png"); game.load.image("bar", "images/powerbar.png"); game.load.image("block", "images/block.png"); }, create: function() { this.power = 0; //turn the background sky blue game.stage.backgroundColor = "#00ffff"; //add the ground this.ground = game.add.sprite(0, game.height * .9, "ground"); //add the hero in this.hero = game.add.sprite(game.width * .2, this.ground.y - 25, "hero"); //add the power bar just above the head of the hero this.powerBar = game.add.sprite(this.hero.x + 25, this.hero.y - 25, "bar"); this.powerBar.width = 0; //start the physics engine game.physics.startSystem(Phaser.Physics.ARCADE); //enable the hero for physics game.physics.enable(this.hero, Phaser.Physics.ARCADE); game.physics.enable(this.ground, Phaser.Physics.ARCADE); this.hero.body.gravity.y = 200; this.hero.body.collideWorldBounds = true; this.ground.body.immovable = true; //set listeners game.input.onUp.add(this.mouseUp, this); game.input.onDown.add(this.mouseDown, this); }, mouseDown: function() { this.timer = game.time.events.loop(Phaser.Timer.SECOND / 1000, this.increasePower, this); }, mouseUp: function() { this.doJump(); game.time.events.remove(this.timer); this.power = 0; this.powerBar.width = 0; }, increasePower: function() { this.power++; this.powerBar.width = this.power; if (this.power > 50) { this.power = 50; } }, doJump: function() { this.hero.body.velocity.y = -this.power * 12; }, update: function() { game.physics.arcade.collide(this.hero, this.ground); } }
Here is the result:
If the example above isn’t working correctly, click here to open in a new tab
One thing you’ll notice is that the jump doesn’t always happen! I’ll be providing a fix for that in the next lesson.