Understanding signal dispatch with Phaser
Talking about HTML5, Javascript and Phaser.
Learn cross platform HTML5 game development
Check my Gumroad page for commented source code, games and books.
var game;
window.onload = function() {
game = new Phaser.Game(480, 640, Phaser.AUTO, "");
game.state.add("PlayGame", playGame);
game.state.start("PlayGame");
}
var playGame = function(game){};
playGame.prototype = {
create: function(){
this.myVar = "hello world";
console.log(this.myVar);
}
}
hello world
What happens if the same console.log line is executed inside a callback function, for example after an input?
var game;
window.onload = function() {
game = new Phaser.Game(480, 640, Phaser.AUTO, "");
game.state.add("PlayGame", playGame);
game.state.start("PlayGame");
}
var playGame = function(game){};
playGame.prototype = {
create: function(){
this.myVar = "hello world";
game.input.onDown.add(function(){
console.log(this.myVar)
})
}
}
Now myVar content is lost, we can’t retrieve it when we click or tap:
undefined
This happens because we lost the context once we enter the callback function. That’s why Phaser allows us to pass the context next to the callback function, this way:
var game;
window.onload = function() {
game = new Phaser.Game(480, 640, Phaser.AUTO, "");
game.state.add("PlayGame", playGame);
game.state.start("PlayGame");
}
var playGame = function(game){};
playGame.prototype = {
create: function(){
this.myVar = "hello world";
game.input.onDown.add(function(){
console.log(this.myVar)
}, this)
}
}
And now we can access again to myVar value if we click or tap:
hello world
Now, let’s create a class, the most basic class ever, which only prompts some text on the console:
var game;
window.onload = function() {
game = new Phaser.Game(480, 640, Phaser.AUTO, "");
game.state.add("PlayGame", playGame);
game.state.start("PlayGame");
}
var playGame = function(game){};
playGame.prototype = {
create: function(){
this.myVar = "hello world";
game.input.onDown.add(function(){
console.log(this.myVar)
}, this);
var newClass = new NewClass(game);
}
}
NewClass = function (game) {
console.log("I am a new class")
};
NewClass.prototype.constructor = NewClass;
As you can see the text is appearing on the console, followed by myVar content each time we click or tap:
I am a new class
hello world
Now, let’s change things a bit and create a writeMyVar method which simply outpus myVar value, then call it:
var game;
window.onload = function() {
game = new Phaser.Game(480, 640, Phaser.AUTO, "");
game.state.add("PlayGame", playGame);
game.state.start("PlayGame");
}
var playGame = function(game){};
playGame.prototype = {
create: function(){
this.myVar = "hello world";
game.input.onDown.add(function(){
console.log(this.myVar)
}, this);
var newClass = new NewClass(game);
this.writeMyVar();
},
writeMyVar: function(){
console.log("from the function: " + this.myVar);
}
}
NewClass = function (game) {
console.log("I am a new class")
};
NewClass.prototype.constructor = NewClass;
Once you execute the code, we have the messages properly displayed on the console:
I am a new class
from the function: hello world
Problems start when you try to access PlayGame context from inside the new class, trying with a playGame.prototype.writeMyVar();:
var game;
window.onload = function() {
game = new Phaser.Game(480, 640, Phaser.AUTO, "");
game.state.add("PlayGame", playGame);
game.state.start("PlayGame");
}
var playGame = function(game){};
playGame.prototype = {
create: function(){
this.myVar = "hello world";
game.input.onDown.add(function(){
console.log(this.myVar)
}, this);
var newClass = new NewClass(game);
this.writeMyVar();
},
writeMyVar: function(){
console.log("from the function: " + this.myVar);
}
}
NewClass = function (game) {
console.log("I am a new class");
playGame.prototype.writeMyVar();
};
NewClass.prototype.constructor = NewClass;
That’s right, we get an undefined:
I am a new class
from the function: undefined
from the function: hello world
Obviously there are workarounds to fix this, but now it’s time to introduce signals, here is the final script:
var game;
window.onload = function() {
game = new Phaser.Game(480, 640, Phaser.AUTO, "");
game.state.add("PlayGame", playGame);
game.state.start("PlayGame");
}
var playGame = function(game){};
playGame.prototype = {
create: function(){
this.myVar = "hello world";
game.input.onDown.add(function(){
console.log(this.myVar)
}, this);
var newClass = new NewClass(game);
newClass.signal.add(this.writeMyVar, this);
newClass.sendSignal();
this.writeMyVar();
},
writeMyVar: function(){
console.log("from the function: " + this.myVar);
}
}
NewClass = function (game) {
console.log("I am a new class");
this.signal = new Phaser.Signal();
};
NewClass.prototype.constructor = NewClass;
NewClass.prototype.sendSignal = function() {
this.signal.dispatch();
}
And the first thing I am showing you is the script is working:
I am a new class
from the function: hello world
from the function: hello world
Now let’s see the new lines:
Line 17: signal is a NewClass property which is declared at line 28. In this step, we add as callback function writeMyVar method, with this context.
Line 18: We call sendSignal method of NewClass. As you will see, this method only dispatches a signal. In this example we call it manually from the code, in a real world example inside NewClass the signal can be dispatched when a coin is collected / an enemy is killed and so on.
Line 28: this is how we create a new signal.
Line 33: declaration of sendSignal method.
Line 34: finally here is how we dispatch a signal.
And now you should be able to improve the example using the full options available in the official documentation. A real world example which uses signals in an actual game will come in a few days. Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.