A Useful Messaging System
The ability to send game events as messages is a very useful thing indeed. In our projects, we produce different game systems at different times. Sound might be last, or we might add in a scoring system long after the initial game logic is completed. Messages are ideal for this type of scenario.
For instance, take the event of a raptor dying in Raptor Safari. One option–a bad one–is to explicitly reference all neccesary managers in the raptor scripts themselves. So, to add sound we would have to add a call to our sound manager, to add scoring we call a function on our scoring manager, and so on. The problem is we shouldn’t have to edit older scripts to enable functionality in new managers. This is a recipe for errors and programmer collisions (it will be harder to add in real raptor-specific functionality if there is a constant stream of edits to support other parts of the game).
A better paradigm is to have the raptor broadcast a message about its death. This message includes all relevant information: What killed the raptor, where it died, a reference to the raptor object itself, and so on. The message is broadcast with a specific category, like “raptor”, and interested parties sign up to consume messages about this category.
This means we can add functionality about an event without editing the original script. We could add a sound for our raptor’s death, include it in our scoring systems, spawn a particle effect, and more–all without touching the original raptor logic. Perfect! But how do we accomplish this is UnityScript?
C# includes a mechanism to do this called delegates, which is a type that references a method or methods. Unity’s JavaScript doesn’t support delegates, however, and in fact we’re better served with our own system anyway, since we can do additional logic where necessary. Here’s our solution:
Messenger Singleton
We need a single object to keep track of our lists of listeners. When a script wants to listen to some classification of events, like “item” events, it has to call a function on our messenger. The messenger then keeps track of which scripts should recieve messages for which types of events. This looks like:
The actual collection of listeners is very basic. We use a Hashtable of ArrayLists. The Listen() function looks like:
* Adds a listener for a particular type of message
*/
function Listen(listenerType:String, go:GameObject)
{
// if there’s no array for this tracking category, make a new one
if(listeners[listenerType] == null)
{
listeners[listenerType] = new ArrayList();
}
var listener:ArrayList = listeners[listenerType];
// only add to the array if it isn’t already being tracked
if(!listener.Contains(go))
{
listener.Add(go);
}
}
/**
* Register implicitly with a Component instead of GameObject
*/
function Listen(listenerType:String, component:Component)
{
Listen(listenerType, component.gameObject);
}
We use a second function signature that accepts a Component to allow scripts to use this to register as a listener.
Message Class Structure
All messages are their own classes. To send a message you simply instantiate the class. In Minotaur China Shop, a broadcast of the item delivered message looks like:
In this particular case, the message contains the item we delivered to a custom (the first argument), and the customer to which it was delivered (the second argument). Let’s take a look at the actual MessageItemDelievered.js file:
class MessageItemDelivered extends Message
{
// the item that was collected
var item:Item;
// which customer we delievered it to
var customer:BaseCustomer;
function MessageItemDelivered(item:Item, customer:BaseCustomer)
{
this.item = item;
this.customer = customer;
super(“item”);
}
}
We use our message objects to store multiple references and values. Many times we will compute additional values. For instance, for a raptor death event we may calculate the impact of the event as a scalar from 0..1 and store that in the message. If other scripts want to know the severity of the impact they can use this value, while leaving us the flexibility to tune it in a single location. This is one reason delegates wouldn’t serve us very well.
The super(”item”) line calls the constructor on the parent class, Message. This is where we stick our category identifier. You can think of the line as saying “our message is now ready, send out to anyone interested in the item category”.
Receiving Messages
You’ll notice we don’t actually define the function name the message is calling anywhere. We do this implicitly based on the class name. The naming standards we use are messages look like MessageItemDelivered and their corresponding function names look like _ItemDelivered(). The leading underscore lets us know at a glance that the function will be called by the messenger.
The messenger calls the function and sends it the instance of the message. This allows messages to contain as much data as we want, and also to precompute anything expensive once (at message composition instead of per-listener). A listening object might look like:
* Score an item being delievered
*/
function _ItemDelivered(msg:MessageItemDelivered)
{
// do something here
Debug.Log(“customer purchase # “ + msg.customer.itemsPurchased);
}
Because our code editing environment includes JavaScript autocomplete, it’s very easy to write these functions and see which variables a message provides without having to look it up.
Project Organization
One of the nice side effects of using one class per message is visible organization. We keep all of our messages in one folder, so it’s very easy to see which messages are available in a project. This allows collaborators to get an idea of how much functionality is exposed by other systems. If we need to create a new message–the sound designer would like to hook into something else–it’s easy to go in and add new messages, which may prove useful for other functionality later.

Adding New Messages
Adding a new message is relatively painless. We must:
- Create a new MessageSomething class (we copy/paste an existing message)
- Specify the category in the super() call
- Listeners register with the Messenger singleton
- Listeners implement _Something(msg:MessageSomething) function
Performance
Our actual broadcast functionality uses Unity’s SendMessage() function. This isn’t nearly as fast as calling functions directly with your code, but in practice it’s fast enough. You wouldn’t want to be calling multiple messages every frame, but for game events–enemy spawned, enemy killed, powerup acquired–it’s performant enough to be practical.
In our current implementation we also let null values accumulate in the ArrayLists of listeners. This hasn’t caused any problems, because we flush the Messenger along with scene changes. If you are incredibly performance-conscious, or developing for the iPhone, you may want to skip a messaging system altogether. The point of a messaging system isn’t programming performance, but production performance; it’s a fast and efficient way to get things done.
Sample Project
It’s not as complicated as it sounds, actually. In practice we create new messages in just a few minutes, and we haven’t updated the actual Messenger logic in two projects. Here’s a sample project to get you started. If you make any improvements or changes to the project, please let us know by leaving a comment!
November 27th, 2008 at 5:59 am
Nice framework, very similar to what Mike from Hangout presented at Unite. They’re using C# BTW, with generics for the message type; that adds compile-time consistency check, which is pretty nice I think.
I think they registered per message instead of per category, but I’m pretty sure you could do it too (haven’t scrupulously read your code though):
* make extra category classes, that would be pretty much dummies
* register with Messenger.instance.Listen(Item, this);
* fire with super(Item);
In UnityScript you don’t even need typeof() so you actually save the 2 quote characters
Now that I think of it, your category classes could even inherit from Messenger so you’d go Item.instance.Listen(this)… BTW why do you need an instance? Do you need the messenger to be on scene, can’t it just be static?
….. of course all these frameworks seem crude when you’ve tasted the beauty of true .NET events, associated with IDE support!
But I agree it’s a lot of groundwork, and somehow I’ve always stalled being the first one to try it with Unity, I think the webplayer doesn’t like events too much… plus obviously there’s no IDE support.
December 16th, 2009 at 9:22 pm
Any chance that you guys will release a sample project written in Unity 2.6? I’m trying to break into Unity programming, and this seems very helpful, but the system of messages is hard to understand without a working demo (Unity 2.6 isn’t backwards compatible).
December 29th, 2009 at 5:48 pm
Unity 2.6 can open this project. It is backwards compatible (it’s just that older versions aren’t forwards compatible–if we released a 2.6 project people with 2.5 couldn’t open it).