Dispatching Events with Phaser.Signal

The Event Dispatcher

In my opinion, one of the best and most overlooked features of Phaser is the Signal class.  With just a few steps you can create a clean global broadcasting system.  It also eliminates the headache that javascript often causes with scopes and callbacks.

Here’s a quick example to show you how to do that.

I’ll be starting with the basic template and the dot image below.

Let’s create a dot that is either blue or pink and place in a random position. We will make a class that extends Phaser.Group called dot in the js folder.

class Dot extends Phaser.Group
{
	constructor()
	{
		super(game);
		//add sprite
		var s=game.add.sprite(0,0,"dot");
		s.anchor.set(0.5,0.5);
		this.add(s);
		//
		//place at random position on stage
		this.x=game.world.randomX;
		this.y=game.world.randomY;

		//chose a random frame(color)
		s.frame=game.rnd.integerInRange(0, 1);

                //promote to class property to access from 
                //other functions
                this.s=s;


		//add an onInputDown event
		s.inputEnabled=true;
		s.events.onInputDown.add(this.pressed,this);
	}
	pressed()
	{
		//move the dot down and left
		this.x++;
		this.y++;
	}
}

Include the dot.js file in index.html

<!DOCTYPE html>
<html lang="">
<head>
    <meta charset="UTF-8">
    <title>Game Title Here</title>
    <script src="js/phaser.min.js">
    </script>
    <script src="js/main.js"></script>
    <script src="js/stateMain.js"></script>
    <script src="js/dot.js"></script>
</head>
<body>
</body>
</html>

Load the dot sprite sheet in stateMain.js and make a new dot

var StateMain = {
    preload: function() {
        game.load.spritesheet("dot", "images/dots.png", 40, 40);
    },
    create: function() {
        var dot = new Dot();
    },
    update: function() {}
}

Just for reference, this is the main.js which creates the game. We will be modifying it later.

var game;
window.onload = function() {
    var isMobile = navigator.userAgent.indexOf("Mobile");
    if (isMobile == -1) {
        game = new Phaser.Game(480, 640, Phaser.AUTO, "ph_game");
    } else {
        game = new Phaser.Game(window.innerWidth, window.innerHeight, Phaser.AUTO, "ph_game");
    }
    game.state.add("StateMain", StateMain);
    game.state.start("StateMain");
}

 

Run the code in your browser and you’ll get a random dot. Press the dot and it moves down and to the right.

 

 

Now let’s add more dots by surrounding the code used to make the dot with a for loop

var StateMain = {
    preload: function() {
        game.load.spritesheet("dot", "images/dots.png", 40, 40);
    },
    create: function() {
    	for (var i = 0; i < 50; i++) {
    		var dot = new Dot();
    	}
        
    },
    update: function() {}
}

Now everytime you click a dot that single dot moves down. But what if we want to move all of the dots?

We could call to a function using this.parent to loop all the children through the group. This would work in this example but would break if the dot moved to somewhere else, such as another group.

A more elegant solution, and one that once you become used to using it is going to save you a lot of time and trouble.

Introducing Phaser.Signal

Phaser.Signal allows us to have a global broadcasting station, and we can listen to it from anywhere!

In main.js we create a global instance of Phaser.Signal called eventDispatcher (This is a holdover reference from my flash days)

var game;
//create a global reference
var eventDispatcher;
window.onload = function() {
    var isMobile = navigator.userAgent.indexOf("Mobile");
    if (isMobile == -1) {
        game = new Phaser.Game(480, 640, Phaser.AUTO, "ph_game");
    } else {
        game = new Phaser.Game(window.innerWidth, window.innerHeight, Phaser.AUTO, "ph_game");
    }
    //make the event dispatcher
    eventDispatcher = new Phaser.Signal();
    game.state.add("StateMain", StateMain);
    game.state.start("StateMain");
}

Broadcast!

To broadcast an event we simply need to dispatch it

eventDispatcher.dispatch(eventName);

where eventName is a string.

Listen In!

To listen for an event

eventDispacher.add(function,this);

So back to our sample code, let’s move the code in the function pressed in the class dot to its own function called moveMe()

pressed()
{
		
}
moveMe()
{
   //move the dot down and left
    this.x++;
    this.y++;
}

In the now empty function pressed() let’s dispatch an event instead

pressed()
{
    eventDispatcher.dispatch("moveDot");
}

and now listen for that same event by placing this code in the event function.

eventDispatcher.add(this.gotEvent,this);

Then we build the function gotEvent

gotEvent(call)
	{
	 //check for which event
	 //in case we broadcast more than one
	   if (call=="moveDot")
	   {
	    this.moveMe();
	   }
	}

Now clicking a dot will move every dot! Even if you add the dot’s parent changes, like if you add it to another group, the call will still get through

Adding Parameters

But what if we only want to move the same color as the dot that is clicked?

Phaser.Signal allows for a parameter to be passed along with the event. It can be a number, string or object.

We just need to make a few small changes.

Add the parameter to the dispatch, in this case, the frame of the sprite

pressed()
{
    eventDispatcher.dispatch("moveDot",this.s.frame);
}

Add in the parameter as the second parameter of the gotEvent function and check it against the frame of the sprite inside that instance of dot

gotEvent(call,params)
	{
		//check for which event
		//in case we broadcast more than one
		if (call=="moveDot")
		{
			if (params==this.s.frame)
			{
				this.moveMe();
			}			
		}
	}

Now only the color that you click will change!

Leave a Comment