Talking about Bouncy Light game, Game development, HTML5, Javascript and Phaser.
The HTML5 prototype of Bouncy Light game gets an update, and as promised we are going to add falling platforms and commented source code.
The fun part of these “jump over tiles” games lies in having different kind of tiles, each one with its own behaviour, and since it’s a very basic kind of game, the key of success when talking about tile types, is “the more, the better”.
We’ll start with a falling platform: it’s a platform that falls down once the player jumps on it, forcing the ball to reach another platform as quickly as possible. And what if running away from a falling platform you land on another falling platform?
Have a look at the game:
Just click/tap and hold to make ball move, release to stop it. Watch out for falling platforms.
The source code in step 1 was uncommented, there is nothing difficult in it anyway a commented source code is worth a thousand tutorials, and here it is:
let game;
// global game options object, to tune gameplay
let gameOptions = {
// ground position, where 0: top of the screen, 1: bottom of the screen
groundPosition: 3 / 4,
// height of the bouncing ball, in pixel above ground position
ballHeight: 300,
// ball gravity used by ARCADE physics
ballGravity: 2500,
// ball x position, where 0: left of the screen, 1: righ of the screen
ballPosition: 1 / 5,
// platforms speed, in pixels per second
platformSpeed: 950,
// distance range from the center of each platform, in pixels
platformDistanceRange: [150, 250],
// height range of a platform, in pixels from ground position
platformHeightRange: [-100, 100],
// length range of a platform, in pixels
platformLengthRange: [40, 60],
// % of a platform to fall down after being hit
fallingPlatformPercent: 50,
// localStorage string name
localStorageName: "bestballscore3"
}
window.onload = function() {
// game configuration object
let gameConfig = {
type: Phaser.AUTO,
backgroundColor:0x87ceeb,
scale: {
mode: Phaser.Scale.FIT,
autoCenter: Phaser.Scale.CENTER_BOTH,
parent: "thegame",
width: 750,
height: 500
},
physics: {
default: "arcade"
},
scene: playGame
}
game = new Phaser.Game(gameConfig);
window.focus();
}
class playGame extends Phaser.Scene{
constructor(){
super("PlayGame");
}
preload(){
this.load.image("ground", "ground.png");
this.load.image("ball", "ball.png");
}
create(){
// creation of the physics group which will contain all platforms
this.platformGroup = this.physics.add.group();
// ball sprite bound to an ARCADE body
this.ball = this.physics.add.sprite(game.config.width * gameOptions.ballPosition, game.config.height * gameOptions.groundPosition - gameOptions.ballHeight, "ball");
// set ball vertical gravity
this.ball.body.gravity.y = gameOptions.ballGravity;
// set maximum restitution to the ball
this.ball.setBounce(1);
// we will only check ball collision on its bottom side
this.ball.body.checkCollision.down = true;
this.ball.body.checkCollision.up = false;
this.ball.body.checkCollision.left = false;
this.ball.body.checkCollision.right = false;
// make ball physics body a little narrower than its sprite
this.ball.setSize(30, 50, true)
// first platform will be exactly under the ball
let platformX = this.ball.x;
// we are going to create 10 platforms which we'll reuse to save resources
for(let i = 0; i < 5; i++){
// platform creation, as a member of platformGroup physics group
let platform = this.platformGroup.create(0, 0, "ground");
// platform won't physically react to collisions
platform.setImmovable(true);
// method to position the platform
this.placePlatform(platform, platformX)
// define next platform x position
platformX += Phaser.Math.Between(gameOptions.platformDistanceRange[0], gameOptions.platformDistanceRange[1]);
}
// input management
this.input.on("pointerdown", this.movePlatforms, this);
this.input.on("pointerup", this.stopPlatforms, this);
// score stats at zero
this.score = 0;
// retrieve top score from local storage, if any
this.topScore = localStorage.getItem(gameOptions.localStorageName) == null ? 0 : localStorage.getItem(gameOptions.localStorageName);
// text object to display the score
this.scoreText = this.add.text(10, 10, "");
// updateScore method will add its argument to current score and display it
this.updateScore(0);
}
// method to add inc to current score and display it
updateScore(inc){
this.score += inc;
this.scoreText.text = "Score: " + this.score + "\nBest: " + this.topScore;
}
// method to move platform to the left, called when the pointer is pressed
movePlatforms(){
this.platformGroup.setVelocityX(-gameOptions.platformSpeed);
}
// method to stop platforms, called when the pointer is released
stopPlatforms(){
this.platformGroup.setVelocityX(0);
}
// method to place "platform" platform at posX horizontal position
placePlatform(platform, posX){
// set platform x and y position
platform.x = posX;
platform.y = game.config.height * gameOptions.groundPosition + Phaser.Math.Between(gameOptions.platformHeightRange[0], gameOptions.platformHeightRange[1]);
// platform will fall down if it's not the first platform AND if a random number between 1 and 100 is smaller than fallingPlatformPercent value
platform.fallingDown = posX != this.ball.x && Phaser.Math.Between(1, 100) <= gameOptions.fallingPlatformPercent;
// set platform display width
platform.displayWidth = Phaser.Math.Between(gameOptions.platformLengthRange[0], gameOptions.platformLengthRange[1]);
// (re)set platform body and velocity to zero
platform.body.gravity.y = 0;
platform.body.velocity.y = 0;
}
// method to get the rightmost platform, returns the position of the rightmost platform, in pixels
getRightmostPlatform(){
let rightmostPlatform = 0;
this.platformGroup.getChildren().forEach(function(platform){
rightmostPlatform = Math.max(rightmostPlatform, platform.x);
});
return rightmostPlatform;
}
// method to be executed at each frame
update(){
// handle collision between platform group and the ball
this.physics.world.collide(this.platformGroup, this.ball, function(bodyA, bodyB){
// if the platform is set to fall down, then assign it a high vertical gravity
if(bodyB.fallingDown){
bodyB.body.gravity.y = 1000
}
});
// loop through all platforms
this.platformGroup.getChildren().forEach(function(platform){
// if a platform leaves the stage to the left side...
if(platform.getBounds().right < 0){
// increase and show the score
this.updateScore(1);
// reposition the platform
this.placePlatform(platform, this.getRightmostPlatform() + Phaser.Math.Between(gameOptions.platformDistanceRange[0], gameOptions.platformDistanceRange[1]))
}
}, this);
// if the ball falls down...
if(this.ball.y > game.config.height){
// save the best score
localStorage.setItem(gameOptions.localStorageName, Math.max(this.score, this.topScore));
// restart the scene
this.scene.start("PlayGame");
}
}
}
There is more to do, such as adding more platform types and some eye candy effects such as particles, but at the moment that’s all, download the source code and enjoy.
Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.