The basics of double jump concept in an endless runner game like Spring Ninja
Here we are talking about Spring Ninja prototype again.
What about adding a double jump feature to the final HTML5 prototype I showed you in this post.
First, let’s have a look at the result:
Click and hold to jump, and do the same thing while in the air to perform a double jump.
Let’s now have a look at the source code, with the new lines highlighted:
window.onload = function() {
var game = new Phaser.Game(640, 480, Phaser.CANVAS);
var ninja;
var ninjaGravity = 800;
var ninjaJumpPower;
var score=0;
var scoreText;
var topScore;
var powerBar;
var powerTween;
var placedPoles;
var poleGroup;
var minPoleGap = 100;
var maxPoleGap = 300;
var ninjaJumping;
var ninjaFallingDown;
var jumps;
var maxExtraJumps = 1;
var play = function(game){}
play.prototype = {
preload:function(){
game.load.image("ninja", "ninja.png");
game.load.image("pole", "pole.png");
game.load.image("powerbar", "powerbar.png");
},
create:function(){
ninjaJumping = false;
ninjaFallingDown = false;
score = 0;
placedPoles = 0;
jumps = 0;
poleGroup = game.add.group();
topScore = localStorage.getItem("topFlappyScore")==null?0:localStorage.getItem("topFlappyScore");
scoreText = game.add.text(10,10,"-",{
font:"bold 16px Arial"
});
updateScore();
game.stage.backgroundColor = "#87CEEB";
game.physics.startSystem(Phaser.Physics.ARCADE);
ninja = game.add.sprite(80,0,"ninja");
ninja.anchor.set(0.5);
ninja.lastPole = 1;
game.physics.arcade.enable(ninja);
ninja.body.gravity.y = ninjaGravity;
addPole(80);
},
update:function(){
game.physics.arcade.collide(ninja, poleGroup, checkLanding);
if(ninja.y>game.height){
die();
}
}
}
game.state.add("Play",play);
game.state.start("Play");
function updateScore(){
scoreText.text = "Score: "+score+"\nBest: "+topScore;
}
function prepareToJump(){
if(ninja.body.velocity.y==0 || jumps<maxExtraJumps){
jumps++;
powerBar = game.add.sprite(ninja.x,ninja.y-50,"powerbar");
powerBar.width = 0;
powerTween = game.add.tween(powerBar).to({
width:100
}, 1000, "Linear",true);
game.input.onDown.remove(prepareToJump, this);
game.input.onUp.add(jump, this);
}
}
function jump(){
ninjaJumpPower= -powerBar.width*3-100
powerBar.destroy();
game.tweens.removeAll();
ninja.body.velocity.y = ninjaJumpPower*2;
ninjaJumping = true;
powerTween.stop();
game.input.onUp.remove(jump, this);
if(jumps<maxExtraJumps){
game.input.onDown.add(prepareToJump, this);
}
}
function addNewPoles(){
var maxPoleX = 0;
poleGroup.forEach(function(item) {
maxPoleX = Math.max(item.x,maxPoleX)
});
var nextPolePosition = maxPoleX + game.rnd.between(minPoleGap,maxPoleGap);
addPole(nextPolePosition);
}
function addPole(poleX){
if(poleX<game.width*2){
placedPoles++;
var pole = new Pole(game,poleX,game.rnd.between(250,380));
game.add.existing(pole);
pole.anchor.set(0.5,0);
poleGroup.add(pole);
var nextPolePosition = poleX + game.rnd.between(minPoleGap,maxPoleGap);
addPole(nextPolePosition);
}
}
function die(){
localStorage.setItem("topFlappyScore",Math.max(score,topScore));
game.state.start("Play");
}
function checkLanding(n,p){
game.input.onDown.remove(prepareToJump, this);
if(n.body.touching.down){
var border = n.x-p.x
if(Math.abs(border)>23){
n.body.velocity.x=border*2;
n.body.velocity.y=-200;
}
else{
jumps=0;
game.input.onDown.add(prepareToJump, this);
}
var poleDiff = p.poleNumber-n.lastPole;
if(poleDiff>0){
score+= Math.pow(2,poleDiff);
updateScore();
n.lastPole= p.poleNumber;
ninja.x=80;
}
if(ninjaJumping){
ninjaJumping = false;
}
}
else{
ninjaFallingDown = true;
poleGroup.forEach(function(item) {
item.body.velocity.x = 0;
});
}
}
Pole = function (game, x, y) {
Phaser.Sprite.call(this, game, x, y, "pole");
game.physics.enable(this, Phaser.Physics.ARCADE);
this.body.immovable = true;
this.poleNumber = placedPoles;
};
Pole.prototype = Object.create(Phaser.Sprite.prototype);
Pole.prototype.constructor = Pole;
Pole.prototype.update = function() {
if(ninjaJumping && !ninjaFallingDown){
this.body.velocity.x = ninjaJumpPower;
}
else{
this.body.velocity.x = 0
}
if(this.x<-this.width){
this.destroy();
addNewPoles();
}
}
}
Since the game engine has been already built in the previous step, there are only a few new lines to see:
Line 17: defining jumps variable to keep track of consecutive jumps
Line 18: we’ll define another variable to make the script more universal: now you can decide how many extra jumps are allowed
Line 31: at the start of the game, jumps is set to zero
Line 60: we have to add another condition to let the player jump, that is we didn’t reach the extra jumps cap already
Line 61: now let’s increment jump by 1
Line 79: if we did not reach the maximum amount of extra jumps…
Line 80: … we add the listener to trigger mouse/touch input
Line 107: as soon as we touch the ground, re remove the listener
Line 114: if the player landed safely on the ground…
Line 115: reset jumps variable to zero
Line 116: add input listener once again
And we developed double jump. Download the full source code.