5 common mistakes made in Unity

Bit the Raccoon looking at the Unity 3D logo.

By Alan Zucconi, Independent Developer

It is undeniable that Unity has made game development accessible to many people. Whether you like it or not, it is becoming one of the de-facto tools used by independent developers. Its gentle learning curve has been both Unity’s greatest feature and downfall. By simplifying some aspects of game development, it has imposed its own way of doings things. Features which should be trivial can be incredibly challenging if you’re trying to fight against Unity’s logic and workflow. It’s important to understand how Unity works, so that its limitations can actually become a guided path. This post will show some of the most typical mistakes developers make when approaching Unity for the first time.

1. Get the scale of your project right

If you’re planning to use Unity2D or Unity3D physics, it’s very important to get the scale of your project right. The size of an object is measured in meters; when you import it, you should be sure its size is comparable to what it represents. If it’s a car, it should be approximately 2 meters; if it’s a building, it should be 20; a spaceship is 200, and so on. If it isn’t, you should resize it.

Whether you’re using Box2D or NVIDIA® PhysX®, size does matter for Unity. If the scale of your models is not right, you may experience strange behaviours such as objects falling too slowly. It’s tempting to increase the gravity to speed things up, but this will only make the simulation less realistic.

An animation demonstrating how gravity affects the way that three boxes falling will animate at varying distances.

Changing the scale of your project is very challenging: you may have to re-import sprites, models and to manually re-adjust the position of all the objects in your levels. That’s why is so important to get the scale right from the very beginning.

2. Avoid mixing JavaScript and C# scripts

Unity3D allows you to attach scripts to your objects, which can be written either in C# or JavaScript. Choosing one language or the other will not limit the things you can do in your game. However, you should avoid mixing them. Besides the obvious confusion that working with two different languages causes, there are more practical issues you should be aware of. It is not uncommon for a script to access another one. This is very easy if they are both written in the same language, but it gets quite complicated if they aren’t. For instance, if your image effects are written in JavaScript and you want to procedurally change their parameters from a C# script… well, good luck.

 

It’s normal to be undecided about which language to choose for your game. After all, both JavaScript and C# have their pros and cons. If you have previous experience with programming, you should perhaps start using the language you are more familiar with.

3. Do not use the Standard Assets and the Asset Store

If you’re working independently on your game, chances are you may not have experience in all areas of game development. Scripts, models, textures, sounds …it’s understandable why developers are so keen to use the Asset Store. However, using is too often can be the undoing of many games. First of all, you need to be sure that the asset you are buying fits in your game; it’s not uncommon to download scripts which are incompatible with what you’ve been developing so far. There’s another important aspect which has to be taken into consideration: if you’re buying a very popular asset, it means many other games will be using it as well. Over time, this has caused Unity games (especially indie ones) to converge to a similar visual style. All the standard assets Unity comes with are pretty much abused by developers: chromatic aberration, depth of field and outlined toon shading are not as visually appealing as they were before. If that’s the style you’re aiming for, you should try to create your own effect. It may take longer, but it will give a unique look to your game.

4. Learn how Rigidbody objects should be moved

Rigidbodys in Unity have a lot of properties which are hidden from the inspector. An object doesn’t only have a position, but also a speed, an angular velocity, etc. If you change the position of an object by using a script, you are likely to create inconsistencies in these hidden variables. As a result, the physics of your game might become unpredictable. This won’t only reflect on the way your objects move, but also with how collisions handlers are invoked (such as OnTriggerEnter or OnCollisionEnter). By attaching a Rigidbody component to a game object, you are signing a contract which forbids you from messing up with its position.

If you want your object to move, you should add a force (or a torque) to it. Rigidbody has several methods you can refer to (AddForce, AddForceAtPosition, AddExplosiveForce and so on) which you can use to accelerate it realistically. There are cases, however, in which this is not enough: if you have a destination you want to reach, it’s easier to move the object directly. In this case, MovePosition should be used instead.

The physics of your game shouldn’t depend on the framerate of your game, so it’s important to invoke all these functions in FixedUpdate and not in Update.

5. Avoid reflection (GetComponent, SendMessage, Instantiate, Find, etc.)

Unity offers several shortcuts which allow developers to quickly refer to other scripts or objects. The most common is GetComponent, a method used to lookup scripts attached to your objects. According to the official documentation, there are two variants of GetComponent: one takes the name of the component as a string ( GetComponent(“Rigidbody”)) the other its actual type ( GetComponent<Rigidbody>()). The latter should always be preferred, as referring to an object using its type allows the compiler to spot nasty typos at compilation time. In terms of performance, GetComponent is costly, and using it in the Update method of your script will slow down your game. If you need to access another component very often, the best technique is to cache it.

      // Slow
      void Update () {
      Rigidbody r = GetComponent<Rigidbody>
        (); // Invoked every time
        }

        // Fast (caching)
        private Rigidbody r;
        void Start () {
        r = GetComponent<Rigidbody>(); // Invoked only once

Unity also provides a function called SendMessage which allows you to automatically invoke a function on every game object. SendMessage is very slow and can potentially activate unexpected functions in scripts you’d never suspect. If your game massively relies on SendMessage, you should consider migrating to a different pattern. A common alternative is to have a List<> which contains all the scripts that want to receive your messages. This technique is commonly referred to as the observer pattern. Other alternatives which can provide a more efficient way for your scripts to communicate are the publish-subscribe and singleton patterns.

Finally, your game may require the creation of new objects (such as bullets and enemies) by using the Instantiate function. While you don’t really have other ways in Unity to instantiate new objects, there are few tricks you can use to speed up its usage. Rather than referring to the name of a prefab using a string, you should use a reference to the prefab itself.

          // Slow (using the name of the prefab)
          GameObject g = Instantiate(Resources.Load("bullet")) as GameObject;

          // Fast (using a reference to the prefab)
          public GameObject bulletPrefab;
          ...
          GameObject g = Instantiate(bulletPrefab) as GameObject;

 

An image of the Unity 3D editor, highlighting the Bullet, Smoke and Blood prefab options.

Once you have defined a public GameObject property, you can drag a prefab into the field directly from the inspector. This will allow your script to safely access the prefab and avoid typos.

Editors note: If you enjoyed this article, you should definitely check out Alan’s blog , where there are many more Unity tutorials for you to read!

Resources