by

Some less obvious Unity behaviour and quirks

Some of my personal notes on Unity behaviour that you might not find in a basic FAQ but can nevertheless be useful to know. These are true as of Unity 4.5.

  1. The .enabled property of a script (which is also the checkbox for disabling a MonoBehavior in the inspector) will only prevent Start(), Update(), FixedUpdate(), and OnGUI() from executing. e.g. OnCollisionEnter is still called even on “disabled” scripts. Contrary to the current official documentation, Awake() is also still called.
  2. Child particle systems fire as one automatically with the parent.
  3. Invoke takes Time.timeScale into account. So does WaitForSeconds.
  4. If your PSD files appear as a jumbled mess, make sure Maximise Compatibility is turned on in Photoshop.
  5. If lightmapping looks all glitchy, try ticking “generate lightmap UVs” on the model to get Unity to generate its own. Also “lightmap static” needs to be set on the object.
  6. CalcSize includes rich text markup in its calculation, even for styles where it isn’t shown.
  7. Random.Range is min inclusive, max inclusive for floats, and max exclusive for ints. So Random.Range(0, 2.0f) will return from 0 to 2.0, but Random.Range(0, 2) will only return 0 or 1.
  8. Modifying prefabs (via the Project view, or by clicking Apply in the Inspector) doesn’t actually write changes to disk until after you’ve saved. So make sure to Ctrl-S before committing changes or copying a project.
  9. When scenes change, references to objects in that scene (that aren’t using DontDestroyOnLoad) become Null, but only in Unity’s overloaded null check. If you have a reference to it, MyObj == null will be true, !MyObj will be true, but MyObj ?? will return MyObj, since ?? can’t be overloaded. See the blog post here. Unity may be changing this in the future.
  10. Don’t Instantiate anything inside OnDestroy() or it’ll persist in the world after play stops in the editor. Unity even warns you if you try it. Of course, OnApplicationQuit() gets called before OnDestroy(), so you could always set a flag that stops it from happening in the case wher… NO. That rabbit hole is too deep.
  11. Destroying a script (or its GameObject) automatically ends any Coroutines or Invokes on it. Deactivating a GameObject (SetActive(false)) kills any coroutines but has no effect on Invoke or InvokeRepeating – they just keep running. Coroutines are gone, not just paused – calling SetActive(true) won’t bring them back. Setting .enabled = false on a script has no effect on Coroutines or Invoke/InvokeRepeating.

I’m also interested in quirks that other people know about. I posted these on the Unity forums but it didn’t get any interest.

Bonus: Fog equations to match the camera far clip plane with the fog cutoff point:

if( RenderSettings.fogMode == FogMode.Linear ) {
	camera.farClipPlane = RenderSettings.fogEndDistance;
} else if( RenderSettings.fogMode == FogMode.Exponential ) {
	camera.farClipPlane = Mathf.Log( 1f / 0.0019f ) / RenderSettings.fogDensity;
} else if( RenderSettings.fogMode == FogMode.ExponentialSquared ) {
	camera.farClipPlane = Mathf.Sqrt( Mathf.Log( 1f / 0.0019f ) ) / RenderSettings.fogDensity;
}

Extra Bonus: Someone linked me to this glorious Unity Answers response by user Wolfram: http://answers.unity3d.com/questions/217941/onenable-awake-start-order.html
Did you know that OnLevelWasLoaded switches calling order with Awake if a script is disabled (at least as of Unity 3.5)?

Write a Comment

Comment

  1. Very nice post, some were indeed very elusive 🙂

    Here is one more.

    I am not even sure why this happens, but when i used collisions with a collider and no rigidbody attached to the collider object, collisions were wrong. Probably the collider in the part of the skinned mesh where i wanted to simulate collision did not get calculated correctly and appeared as non moved at all comparing to the starting skinned mesh position. To sum up, if collisions dont seem to work right, try adding a rigid body (locked if needed) and see it it works.