Talking about Super Mario Bros game, Game development, HTML5 and Javascript.
Most platform games allow the player to do more than the normal jump. Some feature the double jump, that is the player is able to jump again while jumping (check HTML5 prototype of a Mario Bros game like Lep’s World featuring scrolling, double jump and destructible tiles for more information), some others feature the wall jump.
Yesterday I was playing Super Mario Bros on the Wii with my daughter when I discovered the super jump: if you jump, then once your character touches the ground jump again immediately, Mario will make a bigger jump.
I decided to show you how to add this feature in the prototype I explained in the post Creation of an HTML5 tile based platform game with no engines behind: pure code! so now if you jump, land then jump again in less than 50 milliseconds, you will make an higher jump.
This could add some interesting twists in gameplay, have a look:
Try to reach the upper platform with A and D key to move and W to jump. You won’t be able to reach it, unless you make a super jump.
Jump, and when you touch the ground, jump again as soon as you can!
And this is the source code, with the super jump highlighted:
(function(){ var canvas = document.getElementById("canvas"); // the canvas where game will be drawn var context = canvas.getContext("2d"); // canvas context var levelCols=20; // level width, in tiles var levelRows=15; // level height, in tiles var tileSize=32; // tile size, in pixels var playerCol=5; // player starting column var playerRow=13; // player starting row var playerSize=24; // player size var sizeDiff=tileSize-playerSize; // difference between player and tile size var leftPressed=false; // are we pressing LEFT arrow key? var rightPressed=false; // are we pressing RIGHT arrow key? var upPressed=false; // are we pressing UP arrow key? var downPressed=false; // are we pressing DOWN arrow key? var movementSpeed=3; // the speed we are going to move, in pixels per frame var playerXSpeed=0; // player horizontal speed, in pixels per frame var playerYSpeed=0; // player vertical speed, in pixels per frame var gravityForce=0.5; // gravity acceleration, in pixels per frame per frame var jumpSpeed=9; // jump speed var superJumpSpeed=15; // super jump speed var onTheGround=false; // Boolean variable which says if we are on the ground var jumped=false; // We want to know if the player jumped var lastTouch=0 // Timestamp of your last Jump, when you touched the ground var doubleJumpDelay=50 // Delay from a jump to another in order to make a double jump, in milliseconds var maxFallingSpeed=10; // maximum falling speed var level = [ // the 11x9 level - 1=wall, 0=empty space [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], [1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1], [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,1], [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,1], [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1], [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1] ]; var playerYPos=playerRow*tileSize+sizeDiff/2; // converting Y player position from tiles to pixels var playerXPos=playerCol*tileSize+sizeDiff/2; // converting X player position from tiles to pixels canvas.width=640; // canvas width. Won't work without it even if you style it from CSS canvas.height=480; // canvas height. Same as before // simple key listeners document.addEventListener("keydown", function(ev){ switch(ev.keyCode){ case 65: leftPressed=true; break; case 87: // when we jump? when these three conditions are satisfied: // 1 - we are on the ground // 2 - our vertical speed is equal to zero // 3 - the jump button is released if(onTheGround && playerYSpeed==0 && !upPressed){ console.log(new Date().getTime()-lastTouch); if(new Date().getTime()-lastTouch<doubleJumpDelay){ playerYSpeed=-superJumpSpeed; } else{ playerYSpeed=-jumpSpeed; } jumped=true; onTheGround=false; } upPressed=true break; case 68: rightPressed=true; break; case 83: downPressed=true; break; } }, false); document.addEventListener("keyup", function(ev){ switch(ev.keyCode){ case 65: leftPressed=false; break; case 87: upPressed=false; break; case 68: rightPressed=false; break; case 83: downPressed=false; break; } }, false); // function to display the level function renderLevel(){ // clear the canvas context.clearRect(0, 0, canvas.width, canvas.height); // walls = red boxes context.fillStyle = "#ff0000"; for(i=0;i<levelRows;i++){ for(j=0;j<levelCols;j++){ if(level[i][j]==1){ context.fillRect(j*tileSize,i*tileSize,tileSize,tileSize); } } } // player = green box context.fillStyle = "#00ff00"; context.fillRect(playerXPos,playerYPos,playerSize,playerSize); } // this function will do its best to make stuff work at 60FPS - please notice I said "will do its best" window.requestAnimFrame = (function(callback) { return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback) { window.setTimeout(callback, 1000/60); }; })(); // function to handle the game itself function updateGame() { // no friction or inertia at the moment, so at every frame initial speed is set to zero playerXSpeed=0; playerYSpeed+=gravityForce; // limiting max vertical speed playerYSpeed=Math.min(playerYSpeed,maxFallingSpeed); // updating speed according to key pressed if(rightPressed){ playerXSpeed=movementSpeed } else{ if(leftPressed){ playerXSpeed=-movementSpeed; } else{ if(upPressed){ /*playerYSpeed=-movementSpeed;*/ } else{ if(downPressed){ /*playerYSpeed=movementSpeed;*/ } } } } // updating player position playerXPos+=playerXSpeed; playerYPos+=playerYSpeed; // check for vertical collisions, got to do it first this time var baseCol = Math.floor(playerXPos/tileSize); var baseRow = Math.floor(playerYPos/tileSize); var colOverlap = playerXPos%tileSize>sizeDiff; var rowOverlap = playerYPos%tileSize>sizeDiff; if(playerYSpeed>0){ if((level[baseRow+1][baseCol] && !level[baseRow][baseCol] && rowOverlap) || (level[baseRow+1][baseCol+1] && !level[baseRow][baseCol+1] && colOverlap && rowOverlap)){ playerYPos = baseRow*tileSize+sizeDiff; playerYSpeed=0; onTheGround=true; if(jumped){ lastTouch=new Date().getTime(); jumped=false; } } } if(playerYSpeed<0){ if((!level[baseRow+1][baseCol] && level[baseRow][baseCol]) || (!level[baseRow+1][baseCol+1] && level[baseRow][baseCol+1] && colOverlap)){ playerYPos = (baseRow+1)*tileSize; playerYSpeed=0; } } // check for horizontal collisions var baseCol = Math.floor(playerXPos/tileSize); var baseRow = Math.floor(playerYPos/tileSize); var colOverlap = playerXPos%tileSize>sizeDiff; var rowOverlap = playerYPos%tileSize>sizeDiff; if(playerXSpeed>0){ if((level[baseRow][baseCol+1] && !level[baseRow][baseCol] && colOverlap) || (level[baseRow+1][baseCol+1] && !level[baseRow+1][baseCol] && rowOverlap && colOverlap)){ playerXPos=baseCol*tileSize+sizeDiff; } } if(playerXSpeed<0){ if((!level[baseRow][baseCol+1] && level[baseRow][baseCol]) || (!level[baseRow+1][baseCol+1] && level[baseRow+1][baseCol] && rowOverlap)){ playerXPos=(baseCol+1)*tileSize; } } // rendering level renderLevel(); // update the game in about 1/60 seconds requestAnimFrame(function() { updateGame(); }); } updateGame(); })();
Good super jumping, I hope to see this feature used somehow in your games. Obviously you can also download the 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.