Talking about Mass Attack game, Game development, HTML5, Javascript and Phaser.
You are a die hard Phaser fan, you should know on september 11 Phaser 3 Beta has been released. Although its seems quite far from being finished and there’s almost no docs available, I wanted to put my hands on it and try to create a prototype of an old game (it was released 10 years ago) called Mass Attack which I already showed you in the posts Create a Flash game like Mass Attack and Create an HTML5 game like Mass Attack with Phaser just using tweens (well, almost). I rewrote the prototype using Phaser CE v2.8.7 and Phaser v3.0.0, and this is probably the first Phaser 3 working prototype. Let’s start with the 2.8.7 version: Click-touch and hold to create a sphere, release to drop the sphere, watch it bounce on the balance and move it accordingly. The source code is not commented yet buy it’s pretty straight-forward especially if you read the other posts of the series.
var game;
var gameOptions = {
maxDiameter: 50,
ballGrowingSpeed: 0.5,
balanceFriction: 400
}
window.onload = function(){
game = new Phaser.Game(320, 480, Phaser.CANVAS);
game.state.add("PlayGame", playGame, true);
}
var playGame = function (){};
playGame.prototype = {
preload: function (){
game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
game.scale.pageAlignHorizontally = true;
game.scale.pageAlignVertically = true;
game.stage.disableVisibilityChange = true;
game.stage.backgroundColor = 0x222222;
this.load.image("ball", "ball.png");
this.load.image("balance", "balance.png");
},
create: function (){
this.growBall = false;
this.canPlay = true;
this.balance = [];
for(var i = 0; i < 2; i++){
this.balance[i] = game.add.group();
this.balance[i].weight = 0;
var balanceSprite = game.add.sprite(game.width / 2 * i, 240, "balance");
balanceSprite.anchor.set(0, 0.5);
this.balance[i].add(balanceSprite);
}
game.input.onDown.add(this.placeBall, this);
game.input.onUp.add(this.dropBall, this);
},
placeBall: function(e){
if(!this.growBall && this.canPlay){
this.ball = game.add.sprite(e.x, 0, "ball");
this.ball.anchor.set(0.5);
this.ball.width = 1;
this.ball.height = 1;
this.ball.balance = Math.floor(this.ball.x / (game.width / 2));
this.balance[this.ball.balance].add(this.ball);
this.ball.y = 30 - this.balance[this.ball.balance].y
this.growBall = true;
}
},
dropBall: function(){
if(this.growBall){
this.growBall = false;
this.canPlay = false;
var ballDestination = game.height / 2 - this.balance[this.ball.balance].getChildAt(0).height / 2 - this.ball.height / 2;
this.balance[this.ball.balance].weight += (4 / 3) * Math.PI * Math.pow((this.ball.width / 2), 3);
var ballTween = game.add.tween(this.ball).to({
y: ballDestination
}, 2000, Phaser.Easing.Bounce.Out, true);
ballTween.onComplete.add(this.adjustBalances, this)
}
},
adjustBalances: function(){
var weightDifference = (this.balance[0].weight - this.balance[1].weight) / gameOptions.balanceFriction;
var maxDifference = game.height / 3;
if(weightDifference > maxDifference){
weightDifference =maxDifference;
}
if(weightDifference < -maxDifference){
weightDifference = -maxDifference;
}
for(var i = 0; i < 2; i++){
var balanceTween = game.add.tween(this.balance[i]).to({
y: weightDifference - (2 * i * weightDifference)
}, 2000, Phaser.Easing.Quadratic.Out, true);
balanceTween.onComplete.add(function(){
this.canPlay = true;
}, this);
}
},
update: function(){
if(this.growBall && this.ball.width < gameOptions.maxDiameter){
this.ball.width += gameOptions.ballGrowingSpeed;
this.ball.height += gameOptions.ballGrowingSpeed;
}
}
}
THIS
INSTANCE: I wasn’t able to keep track of this
in my callback functions, so I needed to declare a _this
variable where to store it.
INPUT LISTENERS: the names changed, but all in all they look the same to me.
TWEENS: really smart way to define them, it was the feature I liked the most so far.
GROUPS: they was a pain. I couldn’t move them, I couldn’t tween their x or y position, had to do a lot of workaround and silly math to create the balance movement. Maybe I missed something
SPRITES: I wasn’t able to change width and height on the fly, so I had to make the game work scaling the sprites rather than resizing them.
Have a look at the source code, don’t be scared to see some changes, here are 10 tips that will help you when you are about to learn a new language
var game;
var _this;
var gameOptions = {
maxDiameter: 1,
ballGrowingSpeed: 0.015,
balanceFriction: 400
}
var config = {
type: Phaser.CANVAS,
width: 320,
height: 480
};
window.onload = function(){
game = new Phaser.Game(config);
game.scene.add("PlayGame", playGame, true);
}
var playGame = function (){
_this = this;
};
playGame.prototype = {
preload: function (){
var camera = _this.cameras.add(0, 0, game.width, game.height);
camera.setBackgroundColor("0x222222");
_this.load.image("ball", "ball.png");
_this.load.image("balance", "balance.png");
},
create: function (){
_this.growBall = false;
_this.canPlay = true;
_this.balance = [];
for(var i = 0; i < 2; i++){
_this.balance[i] = _this.add.group();
_this.balance[i].weight = 0;
_this.balance[i].saveYPosition = 0;
var balanceSprite = _this.add.sprite(config.width / 2 * i, 240, "balance");
balanceSprite.setOrigin(0, 0.5);
_this.balance[i].add(balanceSprite);
}
_this.input.events.on("POINTER_DOWN_EVENT", _this.placeBall);
_this.input.events.on("POINTER_UP_EVENT", _this.dropBall);
},
placeBall: function(e){
if(!_this.growBall && _this.canPlay){
var side = Math.floor(e.x / (config.width / 2));
_this.ball = _this.add.sprite(e.x, 30, "ball");
_this.ball.balance = side;
_this.ball.scaleX = 0.1;
_this.ball.scaleY = 0.1;
_this.balance[_this.ball.balance].add(_this.ball);
_this.growBall = true;
}
},
dropBall: function(){
if(_this.growBall){
_this.growBall = false;
_this.canPlay = false;
var ballDestination = config.height / 2 + _this.balance[_this.ball.balance].saveYPosition - _this.balance[_this.ball.balance].children.entries[0].height / 2 - _this.ball.height * _this.ball.scaleY / 2;
_this.balance[_this.ball.balance].weight += (4 / 3) * Math.PI * Math.pow((_this.ball.width * _this.ball.scaleX / 2), 3);
var ballTween = _this.tweens.add({
targets: _this.ball,
y: ballDestination,
duration: 2000,
ease: "Bounce",
onComplete: _this.adjustBalances
});
}
},
adjustBalances: function(){
var weightDifference = (_this.balance[0].weight - _this.balance[1].weight) / gameOptions.balanceFriction;
var maxDifference = config.height / 3;
if(weightDifference > maxDifference){
weightDifference = maxDifference;
}
if(weightDifference < -maxDifference){
weightDifference = -maxDifference;
}
for(var i = 0; i < 2; i++){
var difference = - _this.balance[i].saveYPosition + weightDifference - (2 * i * weightDifference)
_this.balance[i].saveYPosition += difference;
var balanceTween = _this.tweens.add({
targets: _this.balance[i].children.entries,
y: "+=" + difference.toString(),
duration: 2000,
ease: "Quad",
onComplete: function(){
_this.canPlay = true;
}
})
}
},
update: function(){
if(_this.growBall && _this.ball.scaleX < gameOptions.maxDiameter){
_this.ball.scaleX += gameOptions.ballGrowingSpeed;
_this.ball.scaleY += gameOptions.ballGrowingSpeed;
}
}
}
Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.