Common Unity Gotchas

There are a number of “gotchas” that hit pretty much everyone new to Unity programming.  Sometimes these are due to you being new to programming in general, and sometimes it’s due to the fact that Unity uses a slightly unusual method of attaching multiple scripts to a game object.

This overview tries to take you through the ones we see most often on Unity Answers.

The Gotchas

Rigidbody,how does that work?

So you just spent the last 3 days with no sleep, trying to make your object act realistic. You went over most of the physics website to fully understand the principles of gravity, friction, collision and others. But then you hear about Rigidbody and you feel like a growth of anger inside. And you go “Naaa come ooon”

Rigidbody is a component that allows to apply fundamental realistic physics to an object without doing much (or almost).

I want explosion but nothing happens!!!

From the project above you can try to add this code:

if(Input.GetKeyDown(KeyCode.E))
{
    float radius = 10.0F;
    float power = 1000.0F;
    Collider[] colliders = Physics.OverlapSphere (_transform.position, radius);
    foreach(Collider col in colliders)
    {
        if(col.rigidbody != null && col.rigidbody != this.gameObject.rigidbody)
        {
            col.rigidbody.AddExplosionForce (this.power, this._transform.position, this.radius);
	}
}

This code makes sure the actual object is not affected by the explosion. You can now add this to your sphere so that it makes the scaffolding explode.

Simply, you define the radius and the force of the explosion. You collect all colliders around in a certain radius. Then you check which ones have a rigidbody. Finally you check if this rigidbody is not the object.

You just created a bomb.

How to make sure you get OnCollisionXXXX and OnTriggerXXXX functions called in your scripts

In order to collide both objects must have colliders attached.  If you want OnCollisionXXXX then the objects should not have isTrigger set to true, if you want to have OnTriggerXXXX then the objects should have isTrigger set to true.  You must also follow the rules below.

This is one of the most common problems.

There are some two important rules:

You should have a Rigidbody component attached to the game object that has the script containing the OnCollisionXXXX, OnTriggerXXXX methods on it.

This rigidbody can be set to isKinematic = true to ensure that you don’t have physics affecting your object if you don’t want it.

Collision detection is part of the physics system in Unity.  You may not want to use physics for your game, but if you want to use collision detection then you need to add Rigidbody components.  isKinematic = true Rigidbodies do not apply physics to your objects.

At least one of the parties must have a rigidbody that isn’t asleep

To improve performance Unity will put rigidbodies to sleep when they stop moving.  They will be awoken by another rigidbody colliding with them, presuming that body isn’t asleep.  However if you just move or make a collider on an object without a rigidbody, or whose rigidbody is not awake then your collisions will be ignored.

Attach a kinematic rigidbody to any colliders you will create or move if they don’t have a rigidbody already.

Other important considerations

There are a number of other rules that concern what things will make a collision occur.

Mesh colliders will only collide with other mesh colliders if both are convex.  If you need to collide with concave meshes then the other party should be constructed from primitives. See below.
Mesh colliders are one sided – they only collide on the side where the normal is pointing outwards.
Mesh colliders are subject to back face culling.

You can construct colliders for an object out of multiple primitives – this gives you the ability to simulate quite complex objects.  What you need to do is attach multiple child game objects to the object that you want to collide with.  Give that object a rigidbody.  Attach primitive colliders to the child game objects, size and scale them accordingly – the compound shape of them will comprise your new collider.

Getting your Input to work properly

Beginners often end up wondering why their input does not report properly. They set it all up according to the docs (at least they think so) but sometimes they feel nothing is happening. Most of the time, the issue comes up when trying to control some physics via the Input. Since, physics is placed in the FixedUpdate, it would make sense to add the Input there too. Wrong.

Update is machine dependent, that means each computer can  have a different frame rate depending on the processor and the processes actually running on the machine.

FixedUpdate is user-defined. You can modify its value from  the Physics Manager by selecting Edit->Project Settings->Physics from the menu bar. The default value for Fixed Timesteps is 0,02 which represents 50 fps. A smaller value will ask the system to run FixedUpdate faster. Note that the value is a request but the computer on which the game is running might not be able to run at that speed.

Now, Update and FixedUpdate both run independently, it means for one Update, you may have one, many or no FixedUpdate. If your computer runs 100 fps but the FixedUpdate is 50fps that simply means for two Updates we have only one FixedUpdate.

InputFixed

So this is what you should not be doing:

using UnityEngine;

public class Test:MonoBehaviour
{
    void FixedUpdate()
    {
        if(Input.GetKeyDown(KeyCode.Space))
        {
           //Action
        }
    }
}

This is what you could be doing instead:

using UnityEngine;

public class Test:MonoBehaviour
{
    private bool action = false;
    private void Update()
    {
         if(Input.GetKeyDown(KeyCode.Space))
         {
             action = true;
         }
    }
    private void FixedUpdate()
    {
       if(this.action == true)
       {
           //Action
           this.action = false;
        }
    }
}

The Input in the Update is checked every frame guaranteeing no Input gets discarded. A variable is modified in the Update and used in the next call of the FixedUpdate. The boolean is set back to false to ensure that the action does not get repeated endlessly.

How to move with Vector3.Lerp

How to move with Vector3.Lerp

You have your line of code but for some reasons nothing is happening or it all happens at once. Lerp is a interpolation between two points start and to by a ratio t.  So t <=0 the result is the startposition and t >=1 then the result is the to position.

this.transform.position = Vector3.Lerp(start, to, t);

If you want to move between two points exactly in a set amount of time, then you need to record the starting position and increment t (usually by a factor of Time.deltaTime/NumberOfSecondsToComplete) and the object will reach the destination when t reaches 1.

Like this:

private Vector3 start;
private Vector3 target;
private float t;

private void Update()
{
     this.transform.position = Vector3.Lerp(this.start, this.target, t);
     t += Time.deltaTime/2; //Take 2 seconds
}

public void SetTargetPosition(Vector3 newTargetPosition)
{
    this.start = this.transform.position;
    this.target = newTargetPosition;
    this.t = 0f;
}
Otherwise you might want a smoothed effect where you just move from where you currently are towards the target – in that case you use it differently and keep passing the current position as the first Lerp parameter.

In human words, it means you take the <em>start</em>(perhaps transform.position) and you look at <em>to</em>(the target.position). Then you move the object by the amount of t. If you give t= 1 it moves suddenly from <em>start</em> to <em>to</em>. If you give 0.5 it will move 1/2 of the current distance between the two points each frame.
private void Update()
{
    this.transform.position = Vector3.Lerp(this.transform.position, this.target.position, Time.deltaTime);
}

If there would be 10 m between transform(0) and target(10) and deltaTime is 0.2 (20%) then you get:

  1. 20% of target-transform (10-0) = 2m so transform = 2
  2. 20% of target-transform (10-2) = 1.6m so transform = 3.6
  3. 20% of target-transform (10-3.6) = 1.28m so transform = 4.88
  4. And so on

Note that the object will never really get exactly to its destination but more likely get really close, similarly to the limit principle in algebra.

Some examples use Time.time as ratio. This is somehow wrong as your interpolation would only happen in the first second of your scene. Give a value between 0 and 1 considering that 0 will not move at all and 1 will move it all at once, so 0 < t < 1.

How to store lists of objects that can grow

Don’t use Array, ArrayList and HashTable – you should always use one of the .NET generic collections or built in arrays.  The old fashioned collections mean you have to type lots of code to get the object type you want out of them, generic collections remove that problem and can still be made to contain many different types of object if you really need to.
Built in arrays, like int[100], are the fastest and most efficient collections, but you can’t grow or shrink them at runtime.  Use them if you don’t need your array to change its shape

In C# you need to add:

using System.Collections.Generic;

Instead of using Array or ArrayList use generic Lists.  Lists can have items added or removed at runtime, they contain a specific type (or a subclass of that type), they can also be sorted easily and turned into arrays when necessary.

You can use the .NET documentation for List and Dictionary on MSDN.  Simple examples in Unity Script and C# are shown below and should give you the general idea.

You work with Lists like this:

//Define a list using C#
List<int> myList = new List<int>();
List<SomeClass> anotherList = new List<SomeClass>();

//Add element to a list
myList.Add(someValue);

//Add multiple elements to a list
myList.AddRange(someListOrArrayOfValues);

//Clear all elements
myList.Clear();

//Insert into a list
myList.Insert(1, someValue);

//Insert multiple elements
myList.InsertRange(1, someListOrArrayOfValues);

//Remove a specific value
myList.Remove(someValue);

//Remove at a specific index
myList.RemoveAt(1);

//Find an index of an element
var index = myList.IndexOf(someValue);

//Find an index of something using a function in Javascript
var index = anotherList.FindIndex(function(entry) entry.someValue == something);

//Turn a list into an array
var myArray = myList.ToArray();

//Find an index of something using a function in C#
var index = anotherList.FindIndex((entry) => entry.someValue == something)

//Get the number of items in the list
var itemCount = myList.Count

Dictionaries are the .NET generic associative arrays you work with Dictionaries like this:

var myDic = new Dictionary<String, int>();

//Define a dictionary of GameObject to a class in Javascript
var anotherDic = new Dictionary<GameObject, SomeClass>();

//Define a string to int dictionary in C#
Dictionary<string, int> myDic = new Dictionary<string, int>();

//Define a dictionary of GameObject to a class in C#
Dictionary<GameObject, SomeClass>anotherDic = new Dictionary<GameObject, SomeClass>();

//Add an element to a dictionary
myDic["Something"] = someIntValue;

//Get a value from a dictionary
var someValue = myDic["Something"];

//Get a complex value and change one of its properties
anotherDic[gameObject].someProperty = someValue;

//Check if a value exists
if(myDic.ContainsKey("Something") == true) { }

//Remove an element from a dictionary
myDic.Remove("Something');

//Run through all of the values in the dictionary in C#
foreach(int value in myDic.Values) { }

//Clear all elements
myDic.Clear();

//Get the number of items in the dictionary
var count = myDic.Count;

How to configure and move rigidbodies

Physics is your friend, it will simulate lots of things for you, but you have to treat it right!

If you are using the physics system you should use AddForce or the like to move rigidbodies unless they are kinematic.
If you move rigidbodies yourself you must do it in FixedUpdate, but still expect unusual behaviours such as unexpectedly large or small forces being applied to other objects.You cannot use Input functions in FixedUpdate.  If you must get user input, you will need to get it in Update and apply it in FixedUpdate.
Do not change gravity or timescale, if things appear to be moving too quickly or too slowly then the objects are probably not the right size/distance away from the camera, fixing the effect by changing gravity will often cause lots of unexpected errors.  Don’t do it if you are a beginner, get the scale and proportions right.
Use realistic sizes for objects.  Treat 1 world unit as 1 metre, always.  A person is 1.7 metres high, a car is 3.5 metres long etc etc.  Get the sizes right, get the camera the right distance away and you will get the effects you want.  If in doubt examine things in the real world and see how they interact.If your “ball” appears to drop too quickly have you made it the size of a marble?  Try dropping a marble onto your desk – see how fast it moves?  If you were looking for a more “floating” effect you need a much bigger ball, much further away.

What the CharacterController is for

What the CharacterController is for

Character Controller is designed for both the player and NPC characters in a running around and shooting game.  Character Controllers are great for this, they cover a lot of the complicated logic concerning moving platforms, characters blocking other characters etc.

Forget using a character controller if you want Physics to affect your object.  You need to build your own scripts.

Many games just don’t lend themselves to using a Character Controller – so just be sure that is what you want before you commit to it – if you do use it, only use it on the things you need it on.

You can have a Character Controller affect physical objects, for example to push them out of the way.  You need to add some script for that and you cannot always guarantee that it will look realistic as you are interfering with the Physics system when you do this.
Be aware that character controllers don’t have rigidbodies by default and so OnCollisionXXXX and OnTriggerXXXX methods aren’t called by default.  You can add a kinematic rigidbody or handle OnControllerColliderHit.
Always use SimpleMove or Move to move an object that uses a Character Controller.  Do not update the position directly.

How to modify the rotation of an object using Quaternions | Don’t change x,y,z!

How to modify the rotation of an object using Quaternions

The x,y,z,w parameters of a quaternion are nothing to do with the values you see in the inspector for the rotation of an object.  The x,y,z,w variables are not stored in degrees (they are sines and cosines of angles). The rotations in degrees are stored in the .eulerAngles of the rotation.You should not modify x,y,z,w of a Quaternion unless you really know what you are doing.  If you want to change the rotation of something using degrees then modify the .eulerAngles.

If you want to understand Quaternions in detail then it’s a big subject.

To set the angles of an object as seen in the inspector do this:

this.transform.rotation.eulerAngles = new Vector3(100f,0f,100f);

You need to access a C# script from Javascript or vice versa

You can only ever get this access to work in one direction, accessing a Javascript class from a C# file or vice versa.  You can never get two classes to interact with each other in two directions if they are written in two different languages.
Choose one language to write your project in.  If you use 3rd party components that will be completely independent then it doesn’t matter what language they are written in, so long as you put them in one of the locations that is compiled first – Standard Assets, Pro Standard Assets or Plugins and you access them using code that isn’t under one of those special locations.

Javascript and C# are not compiled into the same assembly so you can’t just easily refer to one from the other.  Any code in Plugins, Standard Assets or Pro Standard Assets will be compiled first and so code that isn’t in those directories will have access to all of the scripts and classes that were defined in them.

In this way you can make a C# script access Javascript classes, by putting the Javascript in Standard Assets, Pro Standard Assets or Plugins (or any folder beneath them).  You can make a Javascript script access C# classes by putting the C# classes in a folder beneath Standard Assets, Pro Standard Assets or Plugins.  Remember that Javascript in one of the special folders cannot access C# in any folder and C# in a special folder cannot access Javascript classes no matter where they are.  This is why you shouldn’t try to mix languages in your own project, if you suddenly need access to something you may find that there is no way to get it.

You think you are programming in Java or Javascript with Unity

Firstly Unity says it uses Javascript.  Javascript is not Java, it is not related to Java and only has a few high level similarities.  When Javascript was written it was originally called LiveScript.  Java was popular at the time and it was renamed to make it sound more relevant.
If you are a Java programmer you will find that C# is closer to Java than Unity Javascript. There are many tutorials on moving from Java to C# and they are all totally relevant to C# in Unity.
Javascript in Unity is not Javascript.  Many of us call it Unity Script to make that differentiation.  Javascript in Unity is a .NET language more closely related to Action Script than it is to Javascript.  It has a number of features of Javascript, but many are missing.  It uses classical inheritance rather than prototypical inheritance, you can’t add functions to objects after compilation, the list goes on and on.
Under no circumstances do a real Javascript tutorial or read a real Javascript book and try to apply it to Unity.  You will just end up confused.

Your coroutine doesn’t seem to finish after a wait or yield

This often happens because you have disabled the script containing the coroutine or destroyed the object that the script lives on.  Often when you kill something you want to start a coroutine or use an Invoke to have something happen after a dying animation, a score update or some other delayed process.

Coroutines will execute immediately up to the first yield instruction – so the first part will always run.  If you disable your script or destroy your object the rest of the routine will never execute.
If you use WaitForSeconds then the Time.timeScale must be greater than 0 or your yield will never return.  Remember WaitForSeconds uses game time which is affected by timeScale.
Coroutines run on the object that StartCoroutine is called on.  So if you are starting a coroutine on a different object it makes a lot of sense to use StartCoroutine on that object, not the one you are currently executing.  E.g. otherScript.StartCoroutine(otherScript.SomeFunction());

The wrong way to write a coroutine:

private void Update() 
{
    if(this.health < 0) 
    { 
           StartCoroutine(Die()); 
           Destroy(this.gameObject); //or enabled = false; 
    } 
} 

private IEnumerator Die() 
{ 
       animation.Play("wobble"); 
       yield return new WaitForSeconds(3); 
       //This will never be called 
       animation.Play("die"); 
}

The correct way to write that script would be:

private bool dying = false; 
private void Update() 
{ 
     if(this.dying == true) { return; } 
     if(this.health < 0) 
     { 
         StartCoroutine(Die()); 
     } 
} 

private IEnumerator Die() 
{ 
      this.dying = true; 
      animation.Play("wobble"); 
      yield return new WaitForSeconds(3); 
      animation.Play("die"); 
      yield return new WaitForSeconds(3); 
      Destroy(this.gameObject); 
}

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s