Fixing Unity’s tendency to object coupling: The MessageBus 5


Originally posted in Francisco’s blog

All in all I’m happy enough working with Unity. I mean it has its problems and all, but at Nastycloud we’ve been able to solve most of them successfully and reached a point where we’re super productive using it.

I only have one major thing that bugs me. Unity feels like the PHP of game development. Tons of people are doing things like caveman and creating awful code that doesn’t scale, proudly showing it to other random script kiddies that don’t fullt understand the implications of what they’re doing (or copy-pasting).

This is in some part, Unity’s fault. It allows you to do things that you shouldn’t be doing, or not if you want to work in a team. One of those things, and one that bugs me a lot is its tendency to generate coupled objects.

In a perfect world, every single module of your game should be reusable, classes should talk about themselves, and try not to talk about other classes, or at least not force behaviour on other classes. This is mainly because, when you have a big enough game, having a lot of references to components form here and there easily becomes a code nightmare that slows you down and complicates reading. And I’m all about readable and reusable code. I only tackle performance when performance is an issue, if not, I put readability before.

Unity forces coupling straight from their first tutorial: the player controller hides pickups when colliding with them and it’s also setting the text that the UI needs to show score. That’s absurd. Each pickup should be in charge of hiding itself and UI shouln’t be updated by the player controller, at least not directly. These are the kind of situations that bother me a lot.

In order to solve this, we’ve created a Messaging system that allows objects to broadcast messages when events happen and have other objects subscribe to messages and act accordingly when messages are received.

This is what we called the MessageBus, and in this series of articles I’m going to show you how to build an extensible MessageBus that will allow you to live happy without coupling. Forgetting once and for all of all those public GameObject members that Unity forces you to put all over the place.

Overview of MessageBus pattern

The main goal of this pattern is to allow objects communicate among them but without forcing actions on each other. We’ll achieve this by allowing objects to subscribe to messages and handle messages when they arrive. Each object will have the responsibility to act accordingly to each message it receives.

The MessageBus will be a singleton class that will be in charge of handling MessageSubscribers and broadcasting Messages to them.

Each MessageSubscriber will define to which messages it subscribes, and will also have a MessageHandler that will be poked whenever a Message arrives.

MessageHandlers will be in charge of defining what to do when a Message arrives. Usually you’ll have one script that inherits from MessageHandler per object, overriding the OnMessage() method to do what you want.

Once you want to send a message, you will call MessageBus.SendMessage(message) with a proper instance of the Message class, and it will be broadcasted to all the MessageSubscribers that are listening to the type of that Message instance.

Message

The Message class is the first thing we’ll work on. The goal for it is to communicate which kind of message we’re sending and its parameters.

Message Type

We have two main ways of implementing the message type. One is using a string, such as “PlayerPosition” and the other is creating an enum type that lists all the possible messages.

If your game requires the ability to create message types at runtime (because you don’t know what all the messages are, or because you give your player the ability to create message types for example), you’ll need to use strings.

But beware, using strings is not really happy, mostly because a typo can bring you a few hours of clueless debugging.

Because of this and since we’ll be making use of a nifty feature of Unity, in this article we’ll use an enum type. We’ll create this enum with three message types LevelStart, LevelEnd and PlayerPosition.

public enum MessageType
{
  NONE,
  LevelStart,
  LevelEnd,
  PlayerPosition
}

Now that we have our message types defined, we’ll use a struct to define our messages.

Parameters on messages could be implemented using a Dictionary if you want to pass a lot of data around, but to keep things easy in this article we’ll define just a few members with the most used data types we may want to pass around in our games: int, float, Vector3 and GameObject.

public struct Message
{
    public MessageType Type;
    public int IntValue;
    public float FloatValue;
    public Vector3 Vector3Value;
    public GameObject GameObjectValue;
}

That should cover most of the uses for our messaging system. You can always change this to match your needs.

MessageSubscriber

The message subscriber is just a simple struct too, it stores an array of MessateTypes it will subscribe to and a MessageHandler that will be called each time one of those messages arrives. This subscriber will be saved in the MessageBus and used each time a message is broadcasted.

public struct MessageSubscriber
{
    public MessageType[] MessageTypes;
    public MessageHandler Handler;
}

MessageBus

As previously stated, the message bus has two main responsibilities: subscribing and message broadcasting.

We’ll need to store subscribers in a Dictionary, indexed by MessageType in order to retrieve them easily.

For this on top of MessageBus.cs we need to add

using System.Collections.Generic;

It will allow us to use the polymorphic version of Dictionary that comes with C#.

As the value type for the Dictionary we’ll use C#’s polymorphic List, in order to store a List of MessageSubscribers (the class we’ll build next to define a subscriber).

    Dictionary<MessageType, List<MessageSubscriber>> subscriberLists =
        new Dictionary<MessageType, List<MessageSubscriber>>();

Now, we’ll have to create a method to allow us to register MessageSubscribers and assign them to each message.

    public void AddSubscriber( MessageSubscriber subscriber )
    {
        MessageType[] messageTypes = subscriber.MessageTypes;
        for (int i = 0; i < messageTypes.Length; i++)
            AddSubscriberToMessage (messageTypes[i], subscriber);
    }

Here we’re iterating on each message type that comes defined in the subscriber, and adding it to the list indexed by each of those messages. Let’s write AddSubscriberToMessage now.

    void AddSubscriberToMessage ( MessageType messageType,
                                 MessageSubscriber subscriber)
    {
        if (!subscriberLists.ContainsKey (messageType))
            subscriberLists [messageType] =
                new List<MessageSubscriber> ();

        subscriberLists [messageType].Add (subscriber);
    }

To avoid calling an uninitialized list, we first check if the list of MessageSubscribers was created, if not, we create it. After that, we just add the subscriber to the correct list. As easy as that.

The other responsibility for our MessageBus class is to broadcast messages, so let’s write the SendMessage method:

    public void SendMessage (Message message)
    {
        if (!subscriberLists.ContainsKey (message.Type))
            return;

        List<MessageSubscriber> subscriberList =
            subscriberLists [message.Type];

        for (int i = 0; i < subscriberList.Count; i++)
            SendMessageToSubscriber (message, subscriberList [i]);
    }

This method first looks if the message type actually has subscribers, if it has, it iterates through them and sends the message. Now let’s see how SendMessageToSubscriber works.

    void SendMessageToSubscriber(Message message,
                                 MessageSubscriber subscriber)
    {
        subscriber.Handler.HandleMessage (message);
    }

Simple enough, right? We’re calling the method HandleMessage on our subscriber’s MessageHandler. We’ll get HandleMessage in a moment, but first…

Singleton

In order to make it easy to interact with the MessageBus, we’re going to make it a Singleton. In this way we’ll only have one MessageBus to route our messages and it will be easily accessible from wherever we want in our code.

In order to achieve this we need to create a private static member that will hold the single instance of MessageBus, a static method that returns that instance and also make the constructor private.

    static MessageBus instance;

    public static MessageBus Instance
    {
        get
        {
            if(instance == null)
                instance = new MessageBus();

            return instance;
        }
    }

    private MessageBus() {}

Explaining what a Signleton is and how it works exceeds the scope of this article, but let’s say that now whenever we want to interact with the MessageBus is just a matter of calling MessageBus.Instance.

MessageHandler

Up until now, we’ve been creating raw C# classes, nothing that was strictly Unity related (well, except for using Vector3 and GameObject in the Message struct). But now we’re going to focus on bringing our MessageBus to Unity starting from our MessageHandler. The MessageHandler is going to inherit from MonoBehaviour, and you’ll see why in the next section.

Besides inheriting from MonoBehaviour, MessageHandler is going to be an abstract class. We’ll inherit from it to create our handlers and override the HandleMessage method.

public abstract class MessageHandler : MonoBehaviour
{
    public abstract void HandleMessage( Message message );
}

MessageSubscriberController

This script will be what glues everything inside Unity’s interface, and the reason why the MessageHandler needs to inherit from MonoBehaviour.

MessageSubscriberController will be attached to each GameObject that we want to turn into a message listener. We’re going to add two public members: MessageTypes and Handler, that we’ll be able to make use of UnityEditor to set.

    public MessageType[] MessageTypes;
    public MessageHandler Handler;

And on Start we’ll create a MessageSubscriber and register it.

    void Start()
    {
        MessageSubscriber subscriber = new MessageSubscriber ();
        subscriber.MessageTypes = MessageTypes;
        subscriber.Handler = Handler;

        MessageBus.Instance.AddSubscriber (subscriber);
    }

That’s it! We’re almost done. Now look how cool is this, since we defined MessageType as an enum type, Unity will create a dropdown with all our messages already there to select, and since the public member MessageTypes is an array of MessageType, unity will also create a nice interface to define them. Here you can see a screenshot:

Screen Shot 2015-04-17 at 9.49.27 PM

Fixing Unity’s bad pattern from first tutorial

In order to see this pattern working, I created a GitHub repository with all the code I’ve been discussing in this article plus a fix for Unity’s first tutorial. What I did in that project was mostly to remove responsibilities from PlayerController that shouldn’t be there (hiding pickups, storing score and updating UI) and moving everything to a message based approach, also the camera was coupled to the player, and I fixed it using a PlayerPosition message. 

I hope that, for your teammates sake, you like my changes and think twice before making a public GameObject member next time!


Leave a comment

Your email address will not be published. Required fields are marked *

5 thoughts on “Fixing Unity’s tendency to object coupling: The MessageBus

  • Mick

    Thanks for this great article.

    Last week’s UnityTech’s live training (Apr 13, monday) was about something similar. It hasn’t been uploaded to Unity Live Training archive yet but it’s available to watch on Twitch (http://www.twitch.tv/unitytech/v/4026285).

    There, they explain a Simple Messaging System using UnityEvents and UnityActions.

    What I don’t get, or what I might have missed, is which method (MessageBus or Simple Messaging System with UnityEvents) would be better for different cases.
    I get your code and I believe it is a great implementation, but wouldn’t using Unity’s Event system be more “optimal” since we’re working with Unity?

    Would be great if you could give me any advice on this! And once again, thanks for the great tutorial!

    • francisco Post author

      Our implementation is not actually the same as in the article, it is a little bit more complex (it has a queue and other stuff), but we like it because we’re in control, and can debug it easily, something that we’re not comfortable with Unity’s event system yet. We may do AB testing in the future and find a solution that performs equally or better than Unity’s but that’s something that is not really important for us now, since our games don’t use zillions of messages, and performance hasn’t been a bottleneck yet.

      That said, you can use whatever you’re comfortable with, regarding support, I’d say go with Unity’s since you know who to call if there are problems, but I’d also say that if you’re good enough programmer, having your own solution may (just may) save you some time.

      Thanks for stopping by and comment, I’m happy you found this useful and hope to see you around playing our games! Let us know if you have some games too!

  • Michael

    Thank you for this article; I found it on Gamasutra originally, but decided to read it here. I noticed a slight typo above: “fullt” instead of “fully” when speaking of script kiddies. I’m a 40-something script kiddie myself, having learned how to program via YouTube.

    • Rodrigo Caro

      Hey Michael, thanks! We are glad you you like it. We’ll be launching a greenlight campaign soon. Keep in touch! Cheers!

  • Riley Miller

    I really like this solution, just curious how thread-safe the Singleton pattern is when implemented like this. Any comments?