When I first loaded up Unity some months ago, I got that feeling. You know that feeling. You sense that you’re working with a powerful tool. And there is going to be exciting many things you can do with it. But you also know that because it’s flexible and you can do thing in many different ways, you’re probably going to do it the “wrong way” at first. Over these months I have started to get a better feel for how I’d like to structure my code in Unity and what constructs it provides to help me with that. I’m hoping other beginners can get some ideas from this, and that pros can suggest improvements.

One Script or Many Scripts

When I first started out I was, for the most part, creating one script per game object. I would have a game object, such as Player, which would consist of a number of child objects. This top level object would then have a script component with the same name, which handled everything to do with that entity. This works great to begin with and in some cases probably good enough even in the long run. But more often than not this leads you down a messy hole:

void Update()
 
  {
 
      ...
 
      if (Health < 0 && !IsDead)
 
      {
 
          IsDead = true;
 
          transform.FindChild("BodyMesh").GetComponent().material = _deathMaterial;
 
      }
 
  }

What’s wrong here (besides it being a lame example)? This is what we’d call coupling. We have a method or class which is handling too many things, in this case both state / game logic and presentation. You’ll find this situation often in a game. Based on some event (internal or external) you perform some logic and you change the state of that game entity, and then you want to update what’s presented to the user. Another bit of code that gets crammed in this script is UI code, especially the way Unity handles UI (through the OnGUI() method).

There are many reasons why coupling like this is less than ideal. Here are two which I care about most:

  1. The code becomes exponentially complex. Changes to behavior require you to modify presentation code and changes to presentation forces you to shuffle around behavior code.
  2. Presentation code is not good for unit testing. If the code is mixed up, stubbing out those objects for testing game logic becomes difficult, if not impossible.

The great thing about Unity is also one of its most trivial features. You can have multiple scripts per object! This allows you to break your code up easily. Typically I’ll have one script (with the same name as the object) which contains logic and state, one script which handles UI, and one script that handles visual changes such as animation, texture / material changes, etc. as well as user input. Each of the latter two link to the “parent” class to get their data:

public class PlayerPresentation : MonoBehaviour
 
  {
 
      public Player Player { get; private set; }
 
   
 
      ...
 
   
 
      void Setup()
 
      {
 
          Player = transform.GetComponentInChildren();
 
      }
 
   
 
      void Update()
 
      {
 
          if (Player.JustDied) // Not pretty...this is just for demonstration purposes
 
          {
 
              transform.FindChild("BodyMesh").GetComponent().material = _deathMaterial;
 
          }
 
   
 
          ...
 
      }
 
   
 
      ...
 
  }

As you see I setup the link once so I don’t have to do it every frame. Now if I want to test Player, I can do that without having to worry about stubbing out all the code related to transforms and meshes. In many cases you can and also have scripts on the child objects which update the Presentation based on the state in the master script (if they don’t need their own “logic” script).

Language Features

This isn’t about Unity in itself but when I’m doing game programming, sometimes I can forget about the language features which are available to me. One specific thing that comes to mind is eventing. When thinking about a game there is this sense that everything is happening in a continuous loop and events don’t seem like an obvious choice. As an example, I needed some form of Calendar class that kept track of the date and incremented it. I also had various different scripts which needed to execute a method on a daily or monthly basis. My first instinct was to have the Calendar object manage a list of registered objects (which would implement an interface with the execution method) and call into them. That’d work fine and depending on what you are trying to do, it might be the way to go. But in my case, I realized it’d be much easier just to have the Calendar class (which is a Singleton MonoBehaviour) publish a few events (DayEnded, WeekEnded, MonthEnded) and that way any object that requires it can just register that event. You can see how simple c# makes events, so I had to write a lot less code, and there is good separation of concerns:

public class Calendar : MonoBehaviourSingleton
 
  {
 
      private const float DayLength = 0.5f;
 
      public DateTime Date { get; private set; }
 
      public event EventHandler DayEnded;
 
      ...
 
   
 
      void Awake()
 
      {
 
          Date = new DateTime(2011, 1, 1);
 
          InvokeRepeating("MarkEndOfDay", 0, DayLength);
 
      }
 
   
 
      void MarkEndOfDay()
 
      {
 
          Date = Date.AddDays(1);
 
   
 
          if (DayEnded != null)
 
          {
 
              DayEnded(this, new EventArgs());
 
          }
 
   
 
          ...
 
      }
 
  }

Coroutines: Use Them

This gets mentioned in almost any Unity related article, including several on this blog, so who am I to change the trend? Coroutines seemed scary at first. I was happy doing my time checks in the Update() method every frame. But once I started using Coroutines (I’m specifically talking about InvokeRepeating) I never looked back. It’s amazing how many things in a game you don’t want to do or check every frame. Many of my scripts have ended up with little or no code in the Update method! And even though at first it seems like you are writing more code, you actually end up writing less. Again this is a powerful construct which applies to many situation, so use it creatively.

Time it Just Right

Yet another obvious point which wasn’t so obvious to me when I first started with Unity, was using Awake vs Start and Update vs LateUpdate. Eventually you’ll run into situations where there will be dependencies between initializing and updating of objects and you need to guarantee the order of execution. Generally I’ll use Awake for any internal initialization (no reference is made to other scripts) and occasionally use Start for any cross-script initialization. I have had less use for LateUpdate. I think whenever you feel you need to use it, you have to ask yourself whether there is something in your design that could be changed or improved to remove such execution order dependency. But there are times when it becomes necessary.