IoC Container for Unity3D – part 1

Note: I published the new Svelto.IoC container

Unity is quite a good game development tool, but, although I like most of its features, the code framework is awkward to use on big projects where code maintainability is of fundamental importance.

The considerations in this article do not really apply to simple projects or projects developed by one or two persons. For these specific cases, Unity is good enough. The arguments in this article apply to medium-big projects developed by a medium-big size team.

I will not talk about all the flaws I found, but I will focus on one specifically: how to inject dependencies inside Unity entities. A dependency is defined as an object needed by another object to execute its code. If a class A needs the instance of a class B to execute its code, B is a dependency for A. When B is passed into A, we say that the dependency B is injected into A.

The problem

Unity is based on the concept of “Entity Framework”. An Entity Framework brings many benefits: pushes the users to favor composition over inheritance, keeps the classes small and clean focusing on single responsibilities, promotes modularity. This is in a perfect world.

In Unity, the Entites are called GameObjects and the Components are based on MonoBehaviour implementations. Personally I have some rules I follow when I implement MonoBehaviours for GameObjects:

  1. MonoBehaviours must operate within the GameObjects they are attached to.
  2. MonoBehaviours are reusable between GameObjects , single responsibility classes.
  3. GameObjects should not be created without a view, like a mesh or a colliders or something that is really an entity in the game.
  4. MonoBehaviours can know other components on the same GameObject using GetComponent, however they cannot know MonoBehaviours from other GameObjects.
  5. The behaviour of a GameObject should be extended adding MonoBehaviours instead of adding methods to a single MonoBehaviour.

Unfortunately Unity does not allow to follow most of these rules because of the way dependencies must be solved. In fact what happens if a component needs to communicate with other objects? Let’s say there is a Level object and for some reasons this object must know the monsters that are still alive. When a monster dies, how is it possible to communicate the fact to the Level object?

Currently there are 3 simple solutions to this problem:

  1. Level is a Monobehaviour created inside a GameObject that has no view. All the monsters will look for the Level class using the GameObject.Find call inside the Start or Awake functions and inject themselves into the Level. When the monster dies, will communicate it to the Level through one of its public methods.
  2. Level is a Singleton and it’s used directly inside the monster Monobehaviour.
  3. Like 1, but Level is found through Object.FindObjectOfType.

albeit, I reckon there are problems in following all the three possible solutions:

What’s wrong with GameObject.Find

Beside being quite a slow function, GameObject.Find is one of the example of how awkward the Unity Framework is for big projects development. What happens if someone in a team decides to rename the GameObject? Should GameObjects renames or deletions been forbidden? GameObject.Find can lead to several run-time errors that cannot be caught in compiling time. This scenario could be really hard to manage when dozens and dozens of GameObjects are searched through this function.

What’s wrong with the Singleton

Singleton is a controversial argument since the pattern has been invented. I am personally against the use of Singleton. However if you ask me why I am against the Singleton, I will not answer you with the usual answers (they break encapsulation, hide dependencies, make impossible to write proper unit tests, bind the code to the implementation of a service instead of its abstraction, make refactoring really awkward), but with the hindsight of the practice: your code will become unmanageable after a short term. This because the use of Singletons comes without any design constriction that, while apparently makes the coder life easier, will make it a hell later on, when the code becomes an incomprehensible blob without a structured flow. Projects developed by one of two coders wouldn’t show the problem at first or ever (for example, if the project doesn’t need to be maintained over time), but mid-size projects will pay the consequences of wild design when it’s probably too late for refactoring.

What’s wrong with the Object.FindObjectOfType

How should the Level object be injected inside the Monster class then? There is actually a third solution: calling the function Object.FindObjectOfType. However, what is FindObjectOfType? Object.FindObjectOfType could be seen as a wrong implementation of the Service Locator Pattern, with the difference that it is not possible to abstract the implementation of the service from its interface. This is another problem of Unity framework, Unity seems to hate the concept of interface. Interface is the most powerful concept at the core of every well designed code. Instead to push the coders to use interfaces, Unity pushes the coder to uses Monobehaviour, even when the use of Monobehaviour is not necessary.

The solution

There are 3 ways to resolve dependencies: using the Service Locator pattern, injecting dependencies manually through constructors/setters or automatically with an IoC container and, obviously, using Singletons. Disregarding Singletons, I do not like the Service Locator Pattern because the SLP itself is a singleton (or a static class) and this could lead to some severe limitations compared to the IoC container solution. However using an IoC container in Unity is not simple because Unity does not specify a place where the application can be initialized.

Another article is needed to explain what an IoC container is, therefore I will give a first simple definition: An IoC container is a…container that creates and contains the dependencies that must be injected inside the application objects. It is called Inversion Of Control because the design is created in such a way that the objects are never created by the user, but they are lazily created by the container when they are needed.

There are several IoC containers out there, a lot written in c# as well, but practically no one works in Unity and most of all, they are damn complicated*. For these reasons I decided to create an IoC container for Unity trying to keep it as simple as possible. Actually creating a basic IoC container is pretty straightforward and everybody can do it, my implementation has just a few tweaks that makes it simple to use with Unity projects.

Conclusion (for this article)

The second part of this article (including source code) is now available here:

*Since when I first wrote this article, new IoC containers have been developed. The best ones out there are StrangeIoC, ZenInject and Adic. Google them, it’s worth it.

20 thoughts on “IoC Container for Unity3D – part 1

  1. Hey Sebastiano,

    I have to admit I never used an IoC container before, and I would really be curious to see a continuation to this article, to learn more and maybe change my current design patterns.

    As of now, my solution to the problem is to usually keep my [Level] class as one of many “main” MonoBehaviours of an empty “Brain” GameObject, and then go through a global Notificator (which is the only singleton in my project) that every class uses to send events. Then I just listen to [MonsterBornEvent] / [MonsterDieEvent] from the [Level] class.

  2. Nice article. I’m using a type of IoC by myself and I think it solves most of the described problems well.
    The Object.Find method also have the disadvantage that it looks through all gameobjects in a scene, so this is terribly slow and should not be used easily (may as well apply to Transform.GetChild).
    The singleton pattern may be controversal, but it is imho a valid way to bypass some of these problems for smaller projects, though it’s not a fitting solution for larger projects.

    So I’m looking forward to your next chapter of the article :)

  3. I am quite interested to see an IoC container for Unity3d, as I have been looking around to find one that does work with it. Thanks for your efforts, and sharing them (possibly) with others!

  4. I don’t get it why not just use events?

    Also have you tried Ninject? I’m looking to use it for my future Unity3d projects.

    1. I do use events, but events are not suitable to solve all the communication issues. Moreover two instances must know anyway each other to setup the events communication (unless you use singleton event bus, which I loathe). I actually wrote a little post about events and commands (I use commands widely as well). Another technique I like, but I do not use much, is the mediator communication.

  5. +1 Great stuff you mentioned there! Particularly your points about how GameObjects and MonoBehaviours should be implemented. I’ve had lots of issues before with my GameObjects setup. I wasn’t doing that much wrong ‘seemingly’ but now reading this and thinking back, I see why… Thanks for the article!

  6. Fantastic article that made me start using IoC on Unity in a more organized fashion! (Although I always used IoC on systems development, I had not tried to use it with a dedicated container on Unity until reading this.)

    Upon your proof of concept, I ended up creating a fully IoC container (that grew so much that deserved being released!):

    Anyway, thanks for the great couple of articles!

    1. Thanks André..I will soon blog another article, which clarify very important aspects related to IoC principles. Meanwhile I have tweeted your work 😀

  7. I don’t agree that GameObjects should not be created without a view. It’s useful to have GameObjects without a graphical representation for structuring your game object tree, simplifying transforms and providing logic acting on groups of game objects.

    1. Agreed, but honestly if you create GameObject to manipulate Transforms it’s still a view. My reasoning applies for GameObjects with Monobehaviours that just handle logic outside the GameObject itself, like a manager. Your examples are all valid, except the last one, in case you are talking about a manager of gameobjects.

Leave a Reply