Talking about Dash N Blast game, Game development, HTML5, Javascript and Phaser.
Did you play “Dasn N Blast” game? It’s a fun game available only for iOS devices where you have to move from circle to circle avoiding obstacles, which in most cases are circle arcs rotating around target circles.
The original game is a 3D game built with BuildBox: a tool to design, build, and launch 3D & 2D mobile games without coding.
I have an account with BuildBox so expect some tutorials with it this summer, but at the moment I turned it into a 2D prototype with a top-down view powered by Phaser:
Click or tap to move from one circle to another. The game turned into a vertical endless runner, with incoming circles appearing from the top.
Circles are graphics
objects where circles are actually drawn one by one rather than using sprites.
Object pooling recycles circles leaving the canvas to the bottom to make them appear from the top.
All movements are managed by tweens. The most important thing – obstacles – is still missing because it will feature a bit of trigonometry and will be discussed in step 2, but you can find the completely commented source code:
var game;
// global object containing all configurable options
var gameOptions = {
// number of circles used in the game
numCircles: 4,
// circle min/max radius, in pixels
circleRadiusRange: [150, 200],
// min/max distance between circles, in pixels
circleDistanceRange: [600, 750],
// distance from the bottom of the canvas, in pixels
bottomDistance: 150,
// min/max circle distance from the center of the canvas, in pixels
distanceFromCenter: [0, 150],
// ball speed, in pixels per second
speed: 1000,
// possible circle colors
circleColors: [0x4deeea, 0x74ee15, 0xffe700, 0xf000ff, 0x001eff]
}
window.onload = function() {
let gameConfig = {
type: Phaser.AUTO,
backgroundColor: 0x111111,
scale: {
mode: Phaser.Scale.FIT,
autoCenter: Phaser.Scale.CENTER_BOTH,
parent: "thegame",
width: 750,
height: 1334
},
scene: playGame
}
game = new Phaser.Game(gameConfig);
window.focus();
}
class playGame extends Phaser.Scene{
constructor(){
super("PlayGame");
}
preload(){
this.load.image("ball", "ball.png");
}
create(){
// group which will contain the ball, all circles and landing spots
this.stuffGroup = this.add.group();
// flag to determine if the player can shoot the ball
this.canShoot = true;
// array which will contain all circles
this.circles = [];
// array which will contain all landing spots
this.landingSpots = [];
// index of the circle currently at the bottom of the canvas
this.bottomCircle = 0;
// time to create circles
for(let i = 0; i < gameOptions.numCircles; i++){
// add a graphics object at i-th position of the array
this.circles[i] = this.add.graphics();
// add the graphic object to stuffGroup group
this.stuffGroup.add(this.circles[i]);
// add a sprite representing the landing spot at i-th position of the array
this.landingSpots[i] = this.add.sprite(0, 0, "ball");
// set the landing spot semi-transparent
this.landingSpots[i].alpha = 0.5;
// add landing spot to stuffGroup group
this.stuffGroup.add(this.landingSpots[i]);
// this method will draw a random circle
this.drawCircle(i);
}
// the ball! The hero of our game
this.ball = this.add.sprite(this.circles[0].x, this.circles[0].y, "ball");
// the ball too is added to stuffGroup group
this.stuffGroup.add(this.ball);
// wait for player input then call shootBall method
this.input.on("pointerdown", this.shootBall, this);
}
// method to draw a circle along with its landing area
drawCircle(i){
// clear the graphic object
this.circles[i].clear();
// set graphic line style choosing a random color
this.circles[i].lineStyle(12, Phaser.Utils.Array.GetRandom(gameOptions.circleColors), 1);
// define a random radius
let radius = this.randomOption(gameOptions.circleRadiusRange);
// save the radius as a custom property
this.circles[i].radius = radius;
// place the circle at a random horizontal position
this.circles[i].x = game.config.width / 2 + this.randomOption(gameOptions.distanceFromCenter) * Phaser.Math.RND.sign();
// if both i and bottomCircle are equal to zero, this means it's the first grapic object we are placing
if(i == 0 && this.bottomCircle == 0){
// so we place it at the bottom of the screen
this.circles[i].y = game.config.height - radius - gameOptions.bottomDistance;
}
else{
// otherwise we are placing it above the grapic object in the highest position
this.circles[i].y = this.circles[Phaser.Math.Wrap(i - 1, 0, gameOptions.numCircles)].y - this.randomOption(gameOptions.circleDistanceRange);
}
// time to draw the circle
this.circles[i].strokeCircle(0, 0, radius);
// place the landing spot at circle origin
this.landingSpots[i].x = this.circles[i].x;
this.landingSpots[i].y = this.circles[i].y;
}
// choose a random integer between an option declared in gameOptions object
randomOption(option){
return Phaser.Math.Between(option[0], option[1]);
}
// method to shoot the ball
shootBall(){
// if the player can shoot...
if(this.canShoot){
// can't shoot anymore at the moment
this.canShoot = false;
// define target index, that is the circle at the top of the canvas
let targetIndex = Phaser.Math.Wrap(this.bottomCircle + 1, 0, gameOptions.numCircles);
// calculate distance between the two targets
let distance = Phaser.Math.Distance.Between(this.landingSpots[this.bottomCircle].x, this.landingSpots[this.bottomCircle].y, this.landingSpots[targetIndex].x, this.landingSpots[targetIndex].y);
// add a tween to the ball to move to the target
this.tweens.add({
targets: this.ball,
x: this.landingSpots[targetIndex].x,
y: this.landingSpots[targetIndex].y,
// duration, in milliseconds, is determined according to distance and speed
duration: distance * 1000 / gameOptions.speed,
callbackScope: this,
// once the tween is completed
onComplete: function(){
// determine the amount of pixels to scroll to make top circle move down to the bottom of the canvas
let yScroll = game.config.height - this.circles[targetIndex].radius - gameOptions.bottomDistance - this.circles[targetIndex].y
// add a tween to all stuffGroup children to move them down by yScroll pixels
this.tweens.add({
targets: this.stuffGroup.getChildren(),
props: {
y: {
value: "+=" + yScroll
}
},
duration: 250,
callbackScope: this,
onComplete: function(){
// at the end of the tween, save bottomCircle value
let currentCircle = this.bottomCircle;
// update bottomCircle value
this.bottomCircle = Phaser.Math.Wrap(this.bottomCircle + 1, 0, gameOptions.numCircles);
// redraw the bottom target to be placed at the top
this.drawCircle(Phaser.Math.Wrap(currentCircle, 0, gameOptions.numCircles))
// player can shoot again
this.canShoot = true;
}
})
}
})
}
}
}
The prototype has also room for customization with gameOption
global object.
At the moment the game is fair from being exciting as there is nothing which can kill you, but just wait for next step where evil circle arcs will come into play. 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.