The Hack Spectrum: Tips, Tricks, and Hacks for Unity

Is being quite a while since my last post here! My life is a bit crazy with the moving to Netherlands to work at Paladin Studios, but I saw something this morning that's really amazing! I really want to share you all of you! 

 

Is really amazing everything that has in this presentation and how Ryan Hipple fixed a lot of unity issues with a few customs inspectors and some others stuff! I tried to contact him to see if we can get our hands in this demo, I will update the post if I found something else :)

Convert Text Component to TextMeshProUGUI keeping configurations

For the ones who dosent know, TextMesh Pro is an alternative solution for the Unity Text component, with a lot of more customization and better performance, check some videos / demos here: http://digitalnativestudios.com/

And here is the tool working:

Just to share a quick script that I've done. basically get all instances of the Text component on the current scene, and replace for an new TextMeshPROUGUI one, keeping all your settings, like:

  • Font
  • Color
  • Size
  • Best Fit
  • Alignment
  • Overflow

Worked really well for my purpose, maybe can help someone else, just save the embed script in some editor folder:

Tested with the Unity 4.6.3f1 and Text Mesh Pro Beta v0.1.46 Beta 4.5.1 (you need to get access for this beta on the forum: http://digitalnativestudios.com/forum/ )

Automatically show the build version from Build Settings

I've found this, and has been proved really worth, all that I want is display a label on the menu on my games / apps, when you display the current version of your game, so you can debug things easily when you're trying to found / debug some bugs.

You will need to put this file, inside some Editor folder

What this will do is, as soon you open Unity, he will look for the Version from the Bundle Settings, and generate a new file for you, in this case one like these:
 

So whenever you want to display the current bundle version, just use simple as this:
 

And now you're ready to go :)

There is only a catch, this will be update when you open your unity, and ONLY when you open your Unity, so when you change the bundle version, you need to restart the unity so you get this new version.

Wrapping Unity C# Coroutines for Exception Handling, Value Retrieval, and Locking

Busy weeks lately! But one of things that really drive me crazy is not be able to get exeptions inside coroutines, I know a lot of peoples have this issue as well, and everyone is asking, and one friend of mine show me this:

http://zingweb.com/blog/2013/02/05/unity-coroutine-wrapper/

This is just amazing, you can have call back from a coroutine, try catch and everything we want :D

 

   1:  using UnityEngine;
   2:  using System;
   3:  using System.Collections;
   4:  using System.Collections.Generic;
   5:   
   6:  /// <summary>
   7:  /// Extending MonoBehaviour to add some extra functionality
   8:  /// Exception handling from: http://twistedoakstudios.com/blog/Post83_coroutines-more-than-you-want-to-know
   9:  /// 
  10:  /// 2013 Tim Tregubov
  11:  /// </summary>
  12:  public class TTMonoBehaviour : MonoBehaviour
  13:  {
  14:      private LockQueue LockedCoroutineQueue { get; set; }
  15:              
  16:      /// <summary>
  17:      /// Coroutine with return value AND exception handling on the return value. 
  18:      /// </summary>
  19:      public Coroutine<T> StartCoroutine<T>(IEnumerator coroutine)
  20:      {
  21:          Coroutine<T> coroutineObj = new Coroutine<T>();
  22:          coroutineObj.coroutine = base.StartCoroutine(coroutineObj.InternalRoutine(coroutine));
  23:          return coroutineObj;
  24:      }
  25:      
  26:      /// <summary>
  27:      /// Lockable coroutine. Can either wait for a previous coroutine to finish or a timeout or just bail if previous one isn't done.
  28:      /// Caution: the default timeout is 10 seconds. Coroutines that timeout just drop so if its essential increase this timeout.
  29:      /// Set waitTime to 0 for no wait
  30:      /// </summary>
  31:      public Coroutine<T> StartCoroutine<T>(IEnumerator coroutine, string lockID, float waitTime = 10f)
  32:      {
  33:          if (LockedCoroutineQueue == null) LockedCoroutineQueue = new LockQueue();
  34:          Coroutine<T> coroutineObj = new Coroutine<T>(lockID, waitTime, LockedCoroutineQueue);
  35:          coroutineObj.coroutine = base.StartCoroutine(coroutineObj.InternalRoutine(coroutine));
  36:          return coroutineObj;
  37:      }
  38:      
  39:      /// <summary>
  40:      /// Coroutine with return value AND exception handling AND lockable
  41:      /// </summary>
  42:      public class Coroutine<T>
  43:      {
  44:          private T returnVal;
  45:          private Exception e;
  46:          private string lockID;
  47:          private float waitTime;
  48:          
  49:          private LockQueue lockedCoroutines; //reference to objects lockdict
  50:          private bool lockable;
  51:          
  52:          public Coroutine coroutine;
  53:          public T Value
  54:          {
  55:              get 
  56:              { 
  57:                  if (e != null)
  58:                  {
  59:                      throw e;
  60:                  }
  61:                  return returnVal;
  62:              }
  63:          }
  64:          
  65:          public Coroutine() { lockable = false; }
  66:          public Coroutine(string lockID, float waitTime, LockQueue lockedCoroutines)
  67:          {
  68:              this.lockable = true;
  69:              this.lockID = lockID;
  70:              this.lockedCoroutines = lockedCoroutines;
  71:              this.waitTime = waitTime;
  72:          }
  73:          
  74:          public IEnumerator InternalRoutine(IEnumerator coroutine)
  75:          {
  76:              if (lockable && lockedCoroutines != null)
  77:              {        
  78:                  if (lockedCoroutines.Contains(lockID))
  79:                  {
  80:                      if (waitTime == 0f)
  81:                      {
  82:                          //Debug.Log(this.GetType().Name + ": coroutine already running and wait not requested so exiting: " + lockID);
  83:                          yield break;
  84:                      }
  85:                      else
  86:                      {
  87:                          //Debug.Log(this.GetType().Name + ": previous coroutine already running waiting max " + waitTime + " for my turn: " + lockID);
  88:                          float starttime = Time.time;
  89:                          float counter = 0f;
  90:                          lockedCoroutines.Add(lockID, coroutine);
  91:                          while (!lockedCoroutines.First(lockID, coroutine) && (Time.time - starttime) < waitTime)
  92:                          {
  93:                              yield return null;
  94:                              counter += Time.deltaTime;
  95:                          }
  96:                          if (counter >= waitTime)
  97:                          { 
  98:                              string error = this.GetType().Name + ": coroutine " + lockID + " bailing! due to timeout: " + counter;
  99:                              Debug.LogError(error);
 100:                              this.e = new Exception(error);
 101:                              lockedCoroutines.Remove(lockID, coroutine);
 102:                              yield break;
 103:                          }
 104:                      }
 105:                  }
 106:                  else
 107:                  {
 108:                      lockedCoroutines.Add(lockID, coroutine);
 109:                  }
 110:              }
 111:              
 112:              while (true)
 113:              {
 114:                  try 
 115:                  {
 116:                      if (!coroutine.MoveNext())
 117:                      {
 118:                          if (lockable) lockedCoroutines.Remove(lockID, coroutine);
 119:                          yield break;
 120:                      }
 121:                  }
 122:                  catch (Exception e)
 123:                  {
 124:                      this.e = e;
 125:                      Debug.LogError(this.GetType().Name + ": caught Coroutine exception! " + e.Message + "\n" + e.StackTrace); 
 126:                      if (lockable) lockedCoroutines.Remove(lockID, coroutine);
 127:                      yield break;
 128:                  }
 129:                  
 130:                  object yielded = coroutine.Current;
 131:                  if (yielded != null && yielded.GetType() == typeof(T))
 132:                  {
 133:                      returnVal = (T)yielded;
 134:                      if (lockable) lockedCoroutines.Remove(lockID, coroutine);
 135:                      yield break;
 136:                  }
 137:                  else
 138:                  {
 139:                      yield return coroutine.Current;
 140:                  }
 141:              }
 142:          }
 143:      }
 144:      
 145:      
 146:      /// <summary>
 147:      /// coroutine lock and queue
 148:      /// </summary>
 149:      public class LockQueue
 150:      {
 151:          private Dictionary<string, List<IEnumerator>> LockedCoroutines { get; set; }
 152:          
 153:          public LockQueue()
 154:          {
 155:              LockedCoroutines = new Dictionary<string, List<IEnumerator>>();
 156:          }
 157:          
 158:          /// <summary>
 159:          /// check if LockID is locked
 160:          /// </summary>
 161:          public bool Contains(string lockID)
 162:          {
 163:              return LockedCoroutines.ContainsKey(lockID);
 164:          }
 165:          
 166:          /// <summary>
 167:          /// check if given coroutine is first in the queue
 168:          /// </summary>
 169:          public bool First(string lockID, IEnumerator coroutine)
 170:          {
 171:              bool ret = false;
 172:              if (Contains(lockID))
 173:              {
 174:                  if (LockedCoroutines[lockID].Count > 0)
 175:                  {
 176:                      ret = LockedCoroutines[lockID][0] == coroutine;
 177:                  }
 178:              }
 179:              return ret;
 180:          }
 181:          
 182:          /// <summary>
 183:          /// Add the specified lockID and coroutine to the coroutine lockqueue
 184:          /// </summary>
 185:          public void Add(string lockID, IEnumerator coroutine)
 186:          {
 187:              if (!LockedCoroutines.ContainsKey(lockID))
 188:              {
 189:                  LockedCoroutines.Add(lockID, new List<IEnumerator>());
 190:              }
 191:              
 192:              if (!LockedCoroutines[lockID].Contains(coroutine))
 193:              {
 194:                  LockedCoroutines[lockID].Add(coroutine);
 195:              }
 196:          }
 197:          
 198:          /// <summary>
 199:          /// Remove the specified coroutine and queue if empty
 200:          /// </summary>
 201:          public bool Remove(string lockID, IEnumerator coroutine)
 202:          {
 203:              bool ret = false;
 204:              if (LockedCoroutines.ContainsKey(lockID))
 205:              {
 206:                  if (LockedCoroutines[lockID].Contains(coroutine))
 207:                  {
 208:                      ret = LockedCoroutines[lockID].Remove(coroutine);
 209:                  }
 210:                  
 211:                  if (LockedCoroutines[lockID].Count == 0)
 212:                  {
 213:                      ret = LockedCoroutines.Remove(lockID);
 214:                  }
 215:              }
 216:              return ret;
 217:          }
 218:          
 219:      }
 220:   
 221:  }

You can check for more info here: http://zingweb.com/blog/2013/02/05/unity-coroutine-wrapper/

And thanks Philip for showing that :)
 


 

 

Finding Missing Object References in Unity

Just execute the following code from the menu “Tools/Find Missing references in scene”.

   1:  [MenuItem("Tools/Find Missing references in scene")]
   2:  public static void FindMissingReferences()
   3:  {
   4:      var objects = GameObject.FindObjectsOfType<GameObject>();
   5:   
   6:      foreach (var go in objects)
   7:      {
   8:          var components = go.GetComponents<Component>();
   9:   
  10:          foreach (var c in components)
  11:          {
  12:              SerializedObject so = new SerializedObject(c);
  13:              var sp = so.GetIterator();
  14:   
  15:              while (sp.NextVisible(true))
  16:              {
  17:                  if (sp.propertyType == SerializedPropertyType.ObjectReference)
  18:                  {
  19:                      if (sp.objectReferenceValue == null && sp.objectReferenceInstanceIDValue != 0)
  20:                      {
  21:                          ShowError(FullObjectPath(go), sp.name);
  22:                      }
  23:                  }
  24:              }
  25:          }
  26:      }
  27:  }
  28:   
  29:  private static void ShowError (string objectName, string propertyName)
  30:  {
  31:      Debug.LogError("Missing reference found in: " + objectName + ", Property : " + propertyName);
  32:  }
  33:   
  34:  private static string FullObjectPath(GameObject go)
  35:  {
  36:      return go.transform.parent == null ? go.name : FullObjectPath(go.transform.parent.gameObject) + "/" + go.name;
Source: http://gamasutra.com/blogs/LiorTal/2014120...

Thread in Unity!

Just a quick update about something that I discovered this weekend

Thread Ninja - Multithread Coroutine

Basically what this do is, you can run a heavy task on another thread, this makes the task run keeping the FPS at some acceptable level while running your task, example:

   1:  for(int i = 0 ; i < int.MaxValue; i++)
   2:  {
   3:  }

This will lock your Unity until this finish, but if you make the same thing using the Tread Ninja. the Unity will keep running without problem or slowdown.

   1:  this.StartCoroutineAsync(IEnumeratorYourAsyncRoutine());
   2:   
   3:  IEnumeratorYourAsyncRoutine()
   4:  {
   5:      for(int i =0;i < int.MaxValue; i++)
   6:      {
   7:      }
   8:  }

This is awesome! One big problem using this, if that you can't move anything from Unity inside this coroutine, but if you want you can use this little help here:

   1:  yield return Ninja.JumpToUnity;

This can be a big saver for some things, and best of all, is FREE!

For vs Foreach vs LinQ vs Array vs List - Performance Tests

So, this is something that I always read about it, and I've see a few contradictions here and there, so I've decided to do this test by my own! And see which performance betters compared to the others! 

Populating

So, for the testing purpose I'll just created a simple class here, like this one:

using System;

[Serializable]
public class ClassOne
{
    public float simpleFloat;
    public int simpleInt;
    public string simpleString;

    public ClassOne(float pFloat, int pInt, string pString)
    {
        simpleFloat = pFloat;
        simpleInt = pInt;
        simpleString = pString;
    }
}

And I'll first populate with a 5000 items and create one Array and one List

public class PerformanceTestController : MonoBehaviour 
{

    public List<ClassOne> list = new List<ClassOne>();
    public ClassOne[] array;


    public bool populateList;
    public bool populateArray;


    private void PopulateList()
    {
        Stopwatch tStopwatch = new Stopwatch();
        tStopwatch.Start();
        list = new List<ClassOne>();
        for (int i = 0; i < 1000; i++)
        {
            ClassOne tClassOne = GenerateNewObject();

            list.Add(tClassOne);
        }
        tStopwatch.Stop();
        Debug.Log("Total time to populate a list: " + tStopwatch.Elapsed);
    }

   

    private void PopulateArray ()
    {
        Stopwatch tStopwatch = new Stopwatch();
        tStopwatch.Start();
        array = new ClassOne[1000];
        for (int i = 0 ; i < 1000 ; i++)
        {
            ClassOne tClassOne = GenerateNewObject();

            array[i] = tClassOne;
        }
        tStopwatch.Stop();
        Debug.Log("Total time to populate a array: " + tStopwatch.Elapsed);
    }


    private static ClassOne GenerateNewObject ()
    {
        int tRandomInt = Random.Range(0, 100);
        float tRandomFloat = Random.Range(0f, 100f);
        string tString = string.Format("String test: int = {0}, float = {1}", tRandomInt, tRandomFloat);

        ClassOne tClassOne = new ClassOne(tRandomFloat, tRandomInt, tString);
        return tClassOne;
    }

    void Update()
    {
        if (populateList)
        {
            populateList = false;
            PopulateList();
        }

        if (populateArray)
        {
            populateArray = false;
            PopulateArray();
        }
    }

Result Populating a List vs Array

   The  Array , after 3 tests, seems to be an average of 13.62% faster than populate a List

 

The Array, after 3 tests, seems to be an average of 13.62% faster than populate a List

Update - Populating a list with max items

When you initialize a List without max item setted, the list is initialized with 40 empty items, when you reach the item 41, the list will add more 40 items to the list and goes on, so a few more comparison between the performance in both:

Don't&nbsp;

Don't 



Traveling using foreach - difference between Array and List

Now lets try the difference between the foreach and for in this generated class, using the following methods:

 public void TravelListInForeach()
 {
     Stopwatch tStopwatch = new Stopwatch();
     tStopwatch.Start();
     foreach (ClassOne tClassOne in list)
     {

     }
     tStopwatch.Stop();
     Debug.Log("Total time to run the List using foreach: " + tStopwatch.Elapsed);
 }

public void TravelArrayInForeach ()
{
    Stopwatch tStopwatch = new Stopwatch();
    tStopwatch.Start();
    foreach (ClassOne tClassOne in array)
    {

    }
    tStopwatch.Stop();
    Debug.Log("Total time to run the Array using foreach: " + tStopwatch.Elapsed);
}

Result traveling using foreach

Using the foreach the Array proved to be an average of 647% faster than List

Using the foreach the Array proved to be an average of 647% faster than List


Traveling using for - difference between Array and List

Now lets using a regular for, using these methods:

 public void TravelListInFor ()
 {
     Stopwatch tStopwatch = new Stopwatch();
     tStopwatch.Start();
     for (int i = 0; i < list.Count; i++)
     {
       ClassOne tClassOne = list[i];
     }
     tStopwatch.Stop();
     Debug.Log("Total time to run the List using for: " + tStopwatch.Elapsed);
 }

public void TravelArrayInFor ()
{
    Stopwatch tStopwatch = new Stopwatch();
    tStopwatch.Start();
    for (int i = 0; i < array.Length; i++)
    {
      ClassOne tClassOne = array[i];
    }
    tStopwatch.Stop();
    Debug.Log("Total time to run the Array using for: " + tStopwatch.Elapsed);
}

Result traveling using for

Using a regular for, the Array proved to be an average of 189% faster than List

Using a regular for, the Array proved to be an average of 189% faster than List


Traveling using for - difference between Array and List assign the variable first

I've decided to made more one test using for, but this time saving the Count and the Length in a variable before the for, like this:

 public void TravelListInFor2 ()
 {
     Stopwatch tStopwatch = new Stopwatch();
     tStopwatch.Start();
     int tCount = list.Count;
     for (int i = 0 ; i < tCount ; i++)
     {
       ClassOne tClassOne = list[i];
     }
     tStopwatch.Stop();
     Debug.Log("Total time to run the List using for: " + tStopwatch.Elapsed);
 }

public void TravelArrayInFor2 ()
{
    Stopwatch tStopwatch = new Stopwatch();
    tStopwatch.Start();
    int tLenght = array.Length;
    for (int i = 0 ; i < tLenght ; i++)
    {
      ClassOne tClassOne = array[i];
    }
    tStopwatch.Stop();
    Debug.Log("Total time to run the Array using for: " + tStopwatch.Elapsed);
}

Results

Now the difference between both are not so bigger, but the array still 60% faster than list

Now the difference between both are not so bigger, but the array still 60% faster than list

Just to display, that saving the enumerator before the for, gives a performance increase of 56%

Just to display, that saving the enumerator before the for, gives a performance increase of 56%


Search a regular for 

The code used is here

  public void SearchUsingForOnArray ()
  {
      Stopwatch tStopwatch = new Stopwatch();
      tStopwatch.Start();
      int tCount = array.Length;
      for (int i = 0 ; i < tCount ; i++)
      {
        ClassOne tClassOne = array[i];

        if (tClassOne.simpleInt == 50)
          break;
      }
      tStopwatch.Stop();
      Debug.Log("Total time to search the list using for: " + tStopwatch.Elapsed);
  }
 public void SearchUsingForOnList ()
    {
        Stopwatch tStopwatch = new Stopwatch();
        tStopwatch.Start();
        int tCount = list.Count;
        for (int i = 0 ; i < tCount ; i++)
        {
            ClassOne tClassOne = list[i];

            if(tClassOne.simpleInt == 50)
                break;
        }
        tStopwatch.Stop();
        Debug.Log("Total time to search the list using for: " + tStopwatch.Elapsed);
    }

Results

Again, the performance of the same operation on a Length is outstanding

Again, the performance of the same operation on a Length is outstanding


Searching using LinQ 

code used:

 public void SearchUsingLinqOnList ()
 {
     Stopwatch tStopwatch = new Stopwatch();
     tStopwatch.Start();

     ClassOne tClassOne = list.FirstOrDefault(x => 50 == x.simpleInt);
     tStopwatch.Stop();
     Debug.Log("Total time to search the list using for: " + tStopwatch.Elapsed);
 }

public void SearchUsingLinqOnArray ()
{
    Stopwatch tStopwatch = new Stopwatch();
    tStopwatch.Start();

    ClassOne tClassOne = array.FirstOrDefault(x => 50 == x.simpleInt);
    tStopwatch.Stop();
    Debug.Log("Total time to search the list using for: " + tStopwatch.Elapsed);
}

Results

This is strange! The List is almost 200% times faster than the Array on this case.

This is strange! The List is almost 200% times faster than the Array on this case.

Another thing that I've noticed, when you are using a LinQ on a array, the first time initialization need to generate the enumerator, that's why the first one is so expensive. 

       

 

 

 

 

Conclusion

After this tests, a few last comments here:

- I'm not a C# or Visual Studio expert, so maybe a few things here that I don't know why
- Array is 99% of the times faster than a List, so use it whenever you can
- The LinQ is not lighter than a regular for, but maintains a clear code in my opinion
- Avoid foreach
- Assign the enumerator to a variable, do not user Count on a for in to a List


That's it guys :)

Few amazing unity tips / tricks

I see this post and reddit, and I'll keep and copy here, so I can update myself with my own tips! 

Original Post:

http://tequibo.com/unity3d-tips/

Showing private variables in inspector.

Showing private variables in inspector.

Adding multiple prefabs in component’s list in the editor. Note: will not maintain order of items

Adding multiple prefabs in component’s list in the editor. Note: will not maintain order of items

Removing empty entry from an array

Removing empty entry from an array

Making empty gameobject visible only in editor

Making empty gameobject visible only in editor

Dealing with parenting and scrolling

Dealing with parenting and scrolling

Showing gizmos, colliders and raycasts (with Debug.DrawRay) IN GAME WINDOW while in play mode, works for selected objects only

Showing gizmos, colliders and raycasts (with Debug.DrawRay) IN GAME WINDOW while in play mode, works for selected objects only

Palett Picker - Unity Plugin

I've been looking around for some good Pallet solution for unity, cause sometimes is kind of hard keep every necessary colors for each project in a good place.

Them I found this:
https://github.com/prime31/PaletteKit

Is a pretty amazing tool to Load / Save / Export Pallet colors, is basically made to work together with the ProBuilder, but can be used wherever you like, I'm using a lot with NGUI:
 

Pick color for NGUI

The amazing thing about this plugin is this little box floating over the scene view, where you will have all your needed colors in hand:

To add new colors is pretty simple too:

add-new-color


If you want more detail, check this video about the plugin: