Gamasutra: The Art & Business of Making Gamesspacer
View All     RSS
November 26, 2014
arrowPress Releases
November 26, 2014
PR Newswire
View All
View All     Submit Event






If you enjoy reading this site, you might also want to check out these UBM Tech sites:


 
A Simple Observer Pattern for Unity 4.2
by Darrel Cusey on 08/29/13 01:51:00 pm   Expert Blogs   Featured Blogs

The following blog post, unless otherwise noted, was written by a member of Gamasutra’s community.
The thoughts and opinions expressed are those of the writer and not Gamasutra or its parent company.

 

The Unity Package for this article can be downloaded here.

If you have been developing in Unity for awhile, you probably have found yourself writing code like this:

GameObject.Find("BigBoss").GetComponent.AddHealth(-20F);

Although code like this is fully functional, I am going to propose that you shouldn't be doing it.  Here are some reasons why:

  1. If BigBoss loses its BossManager script in exchange for a generic EnemyManager script, all the scripts that try to reference the BossManager will break (even if EnemyManager does have an AddHealth() function).
  2. Whenever a new script is created that must also be notified of any health changes to BigBoss, you must modify every script that performs those changes (so that it also notifies the new script).
  3. If the AddHealth() function is changed to a UpdateStats() function, this will also break all scripts that reference this funtion.

In other words, what this does is create strong coupling between your classes.  When you do this, each class must have intimate knowledge of the class it is trying to access.  As your project grows, this will leads to hours of wasted time, unnecessarily complex code, and an inflexible framework.

One possible solution to this is to implement an Observer Pattern for your project.  Normally, these kinds of systems can be done with Events, Delegates, and Generics.  However, I would guess that most Indie game developers would struggle with the more esoteric formulations of this design pattern.  And while learning new things is great, sometimes you just want to finish your game.  This article will demonstrate an extremely simplified version of the Observer Pattern that will allow your classes to:

  1. publish and subscribe to events easily;
  2. reduce their coupling with other classes;
  3. easily expand the number and types of messages they can publish/subscribe to.

If you haven't done so already, grab the Unity Package for this article, and open up the MessageManager script so you can follow along.  Let's start with a Process Flow diagram that shows what's going on (time moves from top to bottom):

simple observer 2

 

 

 

 

 

 

 

 

At any point in the program, classes can register their interest in certain events with the MessageManager.  At any other time, any other class can generate a new message and send that message (with all the event information about the event) and send that on to the MessageManager.  The MessageManger will then turn around and send that event to all classes that have registered interest in that event.

The MessageManager knows which classes and methods it should send events to by using a little LINQ code as seen in the SendToListeners() method:

public void SendToListeners(Message m){
 foreach (var f in listeners.FindAll(l => l.ListenFor == m.MessageName)){ 
   f.ForwardToObject.BroadcastMessage(f.ForwardToMethod,m,SendMessageOptions.DontRequireReceiver);
   }
 }

There is one caveat to this solution -- namely, all classes that will participate in publishing and subscribing to messages must have a reference to the MessageManager object.  Having just one "hard-coded" reference, though, is much better than having hundreds :)

One way you can easily fulfill this requirement (and the method I chose) is to simply make all classes that will be sending and receiving events a child  of the MessageBehaviour class.  We do this by creating an empty object named "World" and attaching the MessageManger script to it.

public class MessageBehaviour : MonoBehaviour {
protected MessageManager Messenger;
 public void Start(){ 
   Messenger = GameObject.Find("World").GetComponent();
   OnStart();
 }
 protected virtual void OnStart(){
 }
}

...then each of our classes that will participate in publishing and subscribing to messages only needs to inherit from the MessageBehaviour class and implement the OnStart() method:

public class BigBoss : MessageBehaviour {
  protected override void OnStart () {
    // put code here that you would normally put in Start()
  }
}

We'll do something very similar with all Message classes as well -- each one will Inherit from a base Message class.  This still keeps our inheritance hierarchy extremely simple:

simple observer 1

 

 

 

 

 

 

I like using dedicated classes for messages because then I incorporate "convenience functions" right into the message itself.  I didn't do this for this sample, but you can imagine a subscriber needing the message information in a particular format.  Let's say you have an IP address that is represented internally in the class as a 32-bit UINT.  A subscriber may instead need this information as a string -- if your message is a class, then you can simply make a GetIPAddresssString() method in the class which will guarantee that all subscribers re-format the data in exactly the same way.

As you can see though, we need a way for our MessageManager to be able to handle LOTS of different message classes -- some may only have a name/value pair while others could contain dozens of attributes.

To allow any number of different Message classes to be used with this system, we use inheritance again (composition works fine, though, as well).  We use a base Message class, and all other message inherit from it.  Because we are lazy programmers, and don't like re-writing getters and setters for every child class of message, we'll call the base constructor right in the signature like this.  We can see this in the definition of the NewPlayerMessage:

public class NewPlayerMessage : Message {
 public int PlayerGUID {get; set;}
 public NewPlayerMessage(GameObject s,string n,string v, int p) : base(s,n,v)
 {
   PlayerGUID = p;
 }
}

Now we can send either a generic Message, or the fancier NewPlayerMessage to the MessageManager's SendToListeners() method.

Some things you may want to add to this system would include (again, I left these out to keep things as simple as possible):

  • An unsubscribe function to allow classes to stop receiving messages that no longer interest them
  • An automatic Message GUID system that would allow all message to have a globablly-unique ID that would be required for...
  • An acknowledgement system to allow classes to acknowledge to the sender that they did in-fact receive a given message

I hope you are able to use this implementation of the Observer pattern in your next Unity project.  

As always, thanks for reading.


Related Jobs

Gameloft New Orleans
Gameloft New Orleans — New Orleans, Louisiana, United States
[11.26.14]

Lead Programmer
Blizzard Entertainment
Blizzard Entertainment — San Francisco, California, United States
[11.26.14]

iOS Engineer, San Francisco
Aechelon Technology, Inc.
Aechelon Technology, Inc. — San Francisco, California, United States
[11.26.14]

Geospatial Engineer
DeNA
DeNA — San Francisco, California, United States
[11.26.14]

Software Engineer, Game Server





Loading Comments

loader image