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.