Do you like my tutorials?

Then consider supporting me on Ko-fi

Talking about Spring Ninja game, Game development, HTML5, Javascript and Phaser.

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.

Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.