Per character text animation in Unity!

For quite some time, I've being working with some simple UI text animations, mostly of the times we just deal with that using tweens, scaling the transform of the object, but inspired by one post on reddit, I create the Text Juicer, a simple tool, where you can configure and animate text, per character, like that:

The project is open source, and is on github:
https://github.com/badawe/Text-Juicer

Feel free to add more effects and send new PRs

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 :)

Infinity list ~ Reusable Cells ~ for NGUI

Hello everyone, I'm a bit of a crunch lately, so this is why I'm not posting so much, but I get some time today, and decided to do a post, about something really useful for unity developers, that want to display like a list of friends or anything like that, but can't rely on having more than 300 game objects on the screen. 

I've made something like this, 3 years ago, but have some bugs, but I get to a stable version! :P
 

But that was really old, and I need this again, I've tested a few solutions on Asset Store, but none of this are really good in my option, then I've found a solution from one guy, that really works REALLY well! 

Here is the link (Thanks guys from OrangeLabsUK):
https://github.com/OrangeLabsUK/InfiniteList_NGUI


I've just made a few update, so is easy to replace the cell, and use in other functions, I've just changed the method PopulateListItemWithIndex to virtual, so I can change the data of this cell. And thats it, perfect, reusable, really light (I'm displaying more than 1000 objects at once, without a single problem

Intercept errors from unity and show a nice popup

I know most of Unity developers, already know about that, but this is something that i discovered not long time ago, and I want to share with you guys,  take a look at the gif bellow


So, this is done pretty simple, Unity has one way so you can grab all the Logs from the editor:

And that's it! 
In addition with that, I strongly advise have something like RayGun this tool, will track your errors and show  a bunch of other useful information, like this:

Errors Count, what is the status, where is happen and a lot more useful information

Update from Lior Tal

RegisterLogCallback is now deprecated in Unity 5.

It suffered from a big issue that it was basically just a delegate (not exposed as an event).
This means that any class that used it was overriding all the other delegates that were assigned to it.

Now that Unity 5 was released, you could use Application.logMessageReceived (event) to achieve the same.
— Lior Tal



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/ )

Unity UI vs NGUI - the learning path

So, I just want to share a few things that I'm discovering in the process, and a few tips and tricks, from a guy who work for the past 3 years only with NGUI

 

The draw calls (Overdraw)

The first thing that I've noticed, is that the draw calls, doing exaclty the same way I do things in NGUI result in a lot more draw calls using the new UI, check this example bellow:

Even object off the screen view, are being draw, and 64 draw calls for something simple like that, is wrong, really wrong

Even object off the screen view, are being draw, and 64 draw calls for something simple like that, is wrong, really wrong

So, the main difference here, from the NGUI, on NGUI when a Widget have alpha 0, this are not draw anymore.  But the same in Unity UI do not work, so you need to actually deactivate every object that you aren't using anymore.  So the solution for this are pretty simple, I already work in a structure that help this a lot, that will be something like this:


Object Controller  (GameObject, Controller Class)  - Content (Game Object, Canvas Group)  -- Objects inside 

Object Controller  (GameObject, Controller Class)
 - Content (Game Object, Canvas Group)
 -- Objects inside 

So, after making this changes, this is the result of the draw calls:

I know that 31 draw calls still not perfect as I want, but there is a lot of dynamic images being loaded from the server, and a lot of dynamic fonts here! I'll do more optimization later, and post here the results! 

 

More few things about Draw Calls (Updated 03/29)

I've decided run a few tests about the Draw Calls to make sure of how this is working exactly, so I've created a new scene, with only one background, here is the result:

 

So 2 draw calls
 - Canvas
 - Background Image

Adding one more image above everything, and this being inside an atlas, the same atlas that we had on for the background image:

Now 3 draw calls
 - Canvas
 - Background Image
 - New Error Sign

WHAT?! They are in the same atlas right?! But images overdrawing something else, will generate more one draw call! :( So if I add one more image side by side with the last error sign

Now with 2 images, that is not overlapping we had 3 draw calls
- Canvas
- Background Image
- Error Sign

 - Additional Error Sign draw call is saved by the batching. 

Now adding one more image, from the same atlas

His next image, the like sign, do not add any more draw calls! (YEY) because is in the same atlas

But what happens when this like sign is in the middle of the 2 errors signs?

3 Draw calls?! 

Ok, that was new for me, I tough that this will generate 2 extra draw calls, but I guess I'm wrong,  but what about we adding a font inside this same example

4 Draw Calls
 - Canvas
 - Background
 - The 3 Images 
- Text

Ok, adding a text generate one more draw call, I'm expecting that, so lest put this text in the middle of the 3 images, and see what happens:

5 Draw Calls,   - Canvas  - Background  - Image  - Text  - Extra 2 Images

5 Draw Calls, 
 - Canvas
 - Background
 - Image
 - Text
 - Extra 2 Images

And what about reuse this same text? This will generate more draw calls of not?

Sadly yes, reusing the same font again, generate one more draw call, so, keep in mind that every TextObject will result in more one draw call =/

So a few things to keep in mind:

  • You can overlap objects without getting additional draw calls (if they are not text with dynamic fonts)
  • Every new text asset will generate new draw calls



This post will be updated regularly 


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...

Fast way to hide a specific Gizmo

Just discovered that, and want to share with you guys.

Sometimes when you are working with a few plugins that have specific gizmos, they can enter in from what you are trying to adjust, one fast way to disable gizmos is just close the current scrips on the target game object, like this: 

Performance Test v2

After a few comments on the reddit, I've decided run a couple of more tests, using a few tips that I get from there, so the new results will be bellow, and first I want to make a few notes here:
 

  • I'm using Unity 4.5.5.1f with Visual Studio 2013
  • All of this are tested on my PC running on the editor, I'll make mobiles builds later
  • If you are looking to this, and thinking this can save the performance on your game, you're probably screwed! This at most of the cases will not BRING a big impact
  • There is a TON of other things to take in considerations besides how fast this performance.
  • Don't take this too serious :)
  • An amazing guy  braaadt show me this link [ http://mattwarren.org/2014/09/19/the-art-of-benchmarking/ ], and I've made a few more tests here, just to make an update and better version about it! 

Now for testing purposes I'll use this Main Method here: 

   1:  public void Profile(string pDescription, int pInteractions, bool pRemoveBestAndWorst, Action pAction)
   2:  {
   3:      //If I want to remove the best and the worst interaction
   4:      if (pRemoveBestAndWorst)
   5:          pInteractions += 2;
   6:   
   7:      //Cleaning the Memory
   8:      GC.Collect();
   9:      GC.WaitForPendingFinalizers();
  10:      GC.Collect();
  11:   
  12:          
  13:   
  14:      //Warm Up the method
  15:      pAction();
  16:      List<TimeSpan> tAllTimes = new List<TimeSpan>();
  17:      for (int i = 0 ; i < pInteractions ; i++)
  18:      {
  19:          Stopwatch tStopwatch = new Stopwatch();
  20:          tStopwatch.Start();
  21:   
  22:          pAction();
  23:   
  24:          tStopwatch.Stop();
  25:          tAllTimes.Add(tStopwatch.Elapsed);
  26:      }
  27:      TimeSpan tAverageTime = GetAverageTime(tAllTimes, pRemoveBestAndWorst);
  28:   
  29:      if (pRemoveBestAndWorst)
  30:          pInteractions -= 2;
  31:   
  32:      Debug.Log("Average time of " + pDescription + " in "+pInteractions+" times is: " + tAverageTime); 
  33:  }
  34:   
  35:  private TimeSpan GetAverageTime (List<TimeSpan> pListOfTimes, bool pRemoveBestAndWorst)
  36:  {
  37:      if (pRemoveBestAndWorst)
  38:      {
  39:          pListOfTimes.Sort((TimeSpan a, TimeSpan b) =>
  40:          {
  41:              b.Ticks.CompareTo(a.Ticks);
  42:              return 0;
  43:          });
  44:   
  45:          //Debug.Log("Removing worst: " + pListOfTimes[0]);
  46:          //Removing the fastest
  47:          pListOfTimes.RemoveAt(0);
  48:   
  49:          //Debug.Log("Removing best: " + pListOfTimes[pListOfTimes.Count - 1]);
  50:          //Removing the slowest
  51:          pListOfTimes.RemoveAt(pListOfTimes.Count - 1);
  52:   
  53:      }
  54:   
  55:   
  56:      double doubleAverageTicks = pListOfTimes.Average(timeSpan => timeSpan.Ticks);
  57:      long longAverageTicks = Convert.ToInt64(doubleAverageTicks);
  58:   
  59:      pListOfTimes.Sort((TimeSpan a, TimeSpan b) => b.CompareTo(a));
  60:   
  61:   
  62:   
  63:      return new TimeSpan(longAverageTicks);
  64:  }
  65:  private TimeSpan GetAverageTime (List<TimeSpan> pListOfTimes, bool pRemoveBestAndWorst)
  66:  {
  67:      if (pRemoveBestAndWorst)
  68:      {
  69:          pListOfTimes.Sort((TimeSpan a, TimeSpan b) =>
  70:          {
  71:              b.Ticks.CompareTo(a.Ticks);
  72:              return 0;
  73:          });
  74:   
  75:          //Debug.Log("Removing worst: " + pListOfTimes[0]);
  76:          //Removing the fastest
  77:          pListOfTimes.RemoveAt(0);
  78:   
  79:          //Debug.Log("Removing best: " + pListOfTimes[pListOfTimes.Count - 1]);
  80:          //Removing the slowest
  81:          pListOfTimes.RemoveAt(pListOfTimes.Count - 1);
  82:   
  83:      }
  84:   
  85:   
  86:      double doubleAverageTicks = pListOfTimes.Average(timeSpan => timeSpan.Ticks);
  87:      long longAverageTicks = Convert.ToInt64(doubleAverageTicks);
  88:   
  89:      pListOfTimes.Sort((TimeSpan a, TimeSpan b) => b.CompareTo(a));
  90:   
  91:   
  92:   
  93:      return new TimeSpan(longAverageTicks);
  94:  }

You can use the above code to test whatever you want, is not a TRUE PROFILER, but sometimes you just want make sure if something that you did, are faster than something before, maybe is useful to someone :)


So, lets do a couple of more tests and see what performance in each way:

Test 1 - An empty method

   1:  Profile("Empty Test", repeatForHowManyTimes, () =>
   2:              {
   3:                  for (int i = 0; i < totalItems; i++)
   4:                  {
   5:                      
   6:                  }
   7:              });

Average time of Method: 0.0000114


Test 2 - Populating an List<T>

   1:   Profile("Populate an List<T>", repeatForHowManyTimes, () =>
   2:              {
   3:                  List<ClassOne> tNewList = new List<ClassOne>();
   4:                  for (int j = 0 ; j < totalItems ; j++)
   5:                  {
   6:                      tNewList.Add(GenerateNewObject());
   7:                  }
   8:              });

Average time of Method: 0.0239758


Test 3 - Populating an Array

   1:  Profile("Populate an Array", repeatForHowManyTimes, () =>
   2:              {
   3:                  ClassOne[] tNewClass = new ClassOne[totalItems];
   4:                  for (int j = 0 ; j < totalItems ; j++)
   5:                  {
   6:                      tNewClass[j] = GenerateNewObject();
   7:                  }
   8:              });

Average time of Method: 0.0234332


Test 4 - Traveling a List<T> using foreach

   1:   List<ClassOne> tNewList = new List<ClassOne>();
   2:  for (int j = 0 ; j < totalItems ; j++)
   3:  {
   4:      tNewList.Add(GenerateNewObject());
   5:  }
   6:   
   7:  Profile("Foreach on a List<T>", repeatForHowManyTimes, () =>
   8:  {
   9:      foreach (ClassOne tClasseOne in tNewList)
  10:      {
  11:   
  12:      }
  13:  });

Average time of Method: 0.0001528


Test 5 - Traveling and Array using foreach

   1:  ClassOne[] tNewClass = new ClassOne[totalItems];
   2:  for (int j = 0 ; j < totalItems ; j++)
   3:  {
   4:      tNewClass[j] = GenerateNewObject();
   5:  }
   6:  Profile("Foreach on a Array", repeatForHowManyTimes, () =>
   7:  {
   8:      foreach (ClassOne tClasseOne in tNewClass)
   9:      {
  10:   
  11:      }
  12:  });
  13:              

Average time of Method: 0.0000192


Test 6 - Traveling a List<T> with the Count on the for

   1:  List<ClassOne> tNewList = new List<ClassOne>();
   2:  for (int j = 0 ; j < totalItems ; j++)
   3:  {
   4:      tNewList.Add(GenerateNewObject());
   5:  }
   6:  Profile("Traveling a List without asgin the Count", repeatForHowManyTimes, () =>
   7:  {
   8:      for (int index = 0 ; index < tNewList.Count ; index++)
   9:      {
  10:          ClassOne tClasseOne = tNewList[index];
  11:      }
  12:  });

Average time of Method: 0.0000658


Test 7 - Traveling a List<T> using for

   1:  List<ClassOne> tNewList = new List<ClassOne>();
   2:  for (int j = 0 ; j < totalItems ; j++)
   3:  {
   4:      tNewList.Add(GenerateNewObject());
   5:  }
   6:  Profile("Traveling a List<T> using For", repeatForHowManyTimes, () =>
   7:  {
   8:      int tCount = tNewList.Count;
   9:      for (int index = 0 ; index < tCount ; index++)
  10:      {
  11:          ClassOne tClasseOne = tNewList[index];
  12:      }
  13:  });

Average time of Method: 0.0000423


Teste 8 - Traveling an Array using For

   1:  ClassOne[] tNewClass = new ClassOne[totalItems];
   2:  for (int j = 0 ; j < totalItems ; j++)
   3:  {
   4:      tNewClass[j] = GenerateNewObject();
   5:  }
   6:  Profile("Traveling a Array using For", repeatForHowManyTimes, removeBestAndWorst, () =>
   7:  {
   8:      int tCount = tNewClass.Length;
   9:      for (int index = 0 ; index < tCount ; index++)
  10:      {
  11:          ClassOne tClasseOne = tNewClass[index];
  12:      }
  13:  });

Average time of Method: 0.0000205


Test 9 - Traveling a List<T> testing for some case

   1:  List<ClassOne> tNewList = new List<ClassOne>();
   2:  for (int j = 0 ; j < totalItems ; j++)
   3:  {
   4:      tNewList.Add(GenerateNewObject());
   5:  }
   6:  Profile("Seraching on a Array interating a List<T>", repeatForHowManyTimes, removeBestAndWorst, () =>
   7:  {
   8:      int tCount = tNewList.Count;
   9:      int tRandomItemToSerach = Random.Range(0, 100);
  10:   
  11:      for (int index = 0 ; index < tCount ; index++)
  12:      {
  13:          ClassOne tClasseOne = tNewList[index];
  14:          if (tClasseOne.simpleInt == tRandomItemToSerach)
  15:          {
  16:   
  17:          }
  18:      }
  19:  });

Average time of Method: 0.0000572


Test 10 - Traveling a Array testing for some case

   1:  ClassOne[] tNewClass = new ClassOne[totalItems];
   2:  for (int j = 0 ; j < totalItems ; j++)
   3:  {
   4:      tNewClass[j] = GenerateNewObject();
   5:  }
   6:  Profile("Seraching on a Array interating for", repeatForHowManyTimes, removeBestAndWorst, () =>
   7:  {
   8:      int tCount = tNewClass.Length;
   9:      int tRandomItemToSerach = Random.Range(0, 100);
  10:   
  11:      for (int index = 0 ; index < tCount ; index++)
  12:      {
  13:          ClassOne tClasseOne = tNewClass[index];
  14:          if (tClasseOne.simpleInt == tRandomItemToSerach)
  15:          {
  16:   
  17:          }
  18:      }
  19:  });

Average time of Method: 0.0000354


Test 11 - Searching on a List<T> using LinQ

   1:  List<ClassOne> tNewList = new List<ClassOne>();
   2:  for (int j = 0 ; j < totalItems ; j++)
   3:  {
   4:      tNewList.Add(GenerateNewObject());
   5:  }
   6:  Profile("Search on a List<T> using LinQ", repeatForHowManyTimes, removeBestAndWorst, () =>
   7:  {
   8:      int tRandomItemToSerach = Random.Range(0, 100);
   9:      ClassOne tFound = tNewList.FirstOrDefault(x => tRandomItemToSerach == x.simpleInt);
  10:  });

Average time of Method: 0.0000178


Test 12 - Inverted for testing case 

   1:  List<ClassOne> tNewList = new List<ClassOne>();
   2:  for (int j = 0 ; j < totalItems ; j++)
   3:  {
   4:      tNewList.Add(GenerateNewObject());
   5:  }
   6:   
   7:  Profile("Inverted Interaction on a List<T>", repeatForHowManyTimes, removeBestAndWorst, () =>
   8:  {
   9:      int tCount = tNewList.Count;
  10:      int tRandomItemToSerach = Random.Range(0, 100);
  11:   
  12:      for (int index = tCount - 1 ; index >= 0 ; index--)
  13:      {
  14:          ClassOne tClasseOne = tNewList[index];
  15:          if (tClasseOne.simpleInt == tRandomItemToSerach)
  16:          {
  17:   
  18:          }
  19:      }
  20:  });

Average time of Method: 0.0000554


Compatarions

Populating a List<T> vs Array

Screenshot_103014_035535_PM.jpg

Traveling using foreach List<T> vs Array

Screenshot_103014_035837_PM.jpg

Traveling a list with the Count as enumerator vs assigned to a variable

Screenshot_103014_040153_PM.jpg

Traveling using for Array vs List<T>

Comparison inside a for List<T> vs Array

Using LinQ vs regular comparision

Regular For vs Inverted For

Last conclusions :)

  •  User regular array if you can, I know sometimes you need to change this size a lot, in this case go with List<T>
  • Assign the variable to a for, (int tCount = tList.Count) bofore the for, boost the performance in more than 55%
  • Using LinQ when you can, is really fast, in my tests about 221% faster.
  • And inverted for, (i--) is 23% slower :P
  • Using a foreach in a Array compared to a list, is 695% faster :P