Unity Game optimization Series part 1: Using Collections and Foreach loop

This blog post is written using experimental approach so without hands-on you may not get the complete idea. Do practice.
While developing a game in unity we often need of loop in it. But recently I got serious issues of game frames performance. Interesting thing was that I am just using two objects and no very high level update functioning.

So the main Objective of this blog is to demonstrate how and when use  of all famous foreach loop or alternate of it in unity. Also we cover some suggestion on using Collection in Unity.

So lets get started.

It is important to note that each Collection that we see in C# have a specific purpose and usage. It is up to us if one collection suits our case. So on wards we will see different collections execution time in Milliseconds for that purpose we will be using stopwatch class.

As from above picture screenshot you can observe basic idea about what we are going to do. In last, we do conclude topic and summarize some suggestions.

If you are not clear about the concept of Collections please review Microsoft docs.Let me explain you a bit about above screenshot. We have Array, List and Dictionary collections and we are concerned about their performance in three cases while inserting data, iterating, iterating using foreach loop, search time and find time in milliseconds.

For hands-on, please create a new scene, create a new script ‘FamousDataStructuresTest ‘ or name of your choice then add following code.

 

Code

Declarations

[Header("Iterations Performance Text Show")]

public Text arrayIterText,listItertext, dicIterText,arrayforeachIterText,listforeachIterText,dicforeachIterText;

[Header("Search Performance Text Show")]

public Text listSearchtext, dicSearchText;

[Header("Find Performance Text Show")]

public Text listFindtext, dicFindText;

[Header("Parameters")]

public Text NoOfItertext;

public int NoOfIter;

int[] intArray;

List<int> intList;

Dictionary<int,int> intDic;

Stopwatch sw;

Start Initializations

void Start()
{

    intArray = new int [NoOfIter];

    intList = new List<int>();

    intDic = new Dictionary<intint> ();

    sw = new Stopwatch();
 
    DataStructuresInsertTime ();

    NoOfItertext.text = NoOfIter.ToString();

}

Data Structures Insertion

  void DataStructuresInsertTime()
  {
   
    // Array
    sw.Start();
    for (int i = 0; i < NoOfIter-1 ; i++) {
      intArray [i] = Random.Range (0,100);
    }

    intArray [intArray.Length - 1] = 111;
    sw.Stop ();
    UnityEngine.Debug.Log ("Elapsed Time Insertion Array "+sw.ElapsedMilliseconds+" ms");
    sw.Reset ();


    // List
    sw.Start();
    for (int i = 0; i < NoOfIter-1 ; i++) {
      intList.Add(Random.Range (0,100));
    }

    intList.Add (111);
    sw.Stop ();
    UnityEngine.Debug.Log ("Elapsed Time Insertion List " + sw.ElapsedMilliseconds+" ms");
    sw.Reset ();


    //Dictionary
    sw.Start();
    for (int i = 0; i < NoOfIter-1; i++)
    {
      intDic.Add(i, Random.Range(0, 100));
    }

    intDic[intDic.Count - 1] = 111;
    sw.Stop ();
    UnityEngine.Debug.Log ("Elapsed Time Insertion Dictionary "+sw.ElapsedMilliseconds+" ms");
    sw.Reset ();

  }

Click Event ‘Array Iteration Time’

  public void onClick_ArrayIterationTime()
  {
    sw.Start ();
    for (int i = 0; i < intArray.Length; i++)
    {

    }
    sw.Stop ();
    arrayIterText.text = sw.ElapsedMilliseconds.ToString()+" ms";
    sw.Reset ();
  }

Other Click Events

    public void onClick_ListIterationTime()
    {
        sw.Start ();
        for (int i = 0; i < intList.Count; i++)
        {
           
        }
        sw.Stop ();
        listItertext.text = sw.ElapsedMilliseconds.ToString()+" ms";
        sw.Reset ();
    }

    public void onClick_DictionaryIterationTime()
    {
        sw.Start ();
        for (int i = 0; i < intDic.Count; i++)
        {

        }
        sw.Stop ();
        dicIterText.text = sw.ElapsedMilliseconds.ToString()+" ms";
        sw.Reset ();
    }

    public void onClick_DictionaryforeachIterationTime()
    {
        sw.Start ();
        foreach (var item in intDic.Keys)
        {

        }
        sw.Stop ();
        dicforeachIterText.text = sw.ElapsedMilliseconds.ToString()+" ms";
        sw.Reset ();
    }

    public void onClick_ArrayIterationforeachTime(int key=111)
    {
        sw.Start ();
        foreach (int a in intArray)
        {

        }
        sw.Stop ();
        arrayforeachIterText.text = sw.ElapsedMilliseconds.ToString()+" ms";
        sw.Reset ();
    }  

    public void onClick_ListIterationforeachTime(int key=111)
    {
        sw.Start ();
        foreach (int a in intList)
        {

        }
        sw.Stop ();
        listforeachIterText.text = sw.ElapsedMilliseconds.ToString()+" ms";
        sw.Reset ();
    }

    public void onClick_ListSearchTime(int key=111)
    {
        sw.Start ();
        bool containsValue = intList.Contains(key);
        sw.Stop ();
        UnityEngine.Debug.Log (containsValue);
        UnityEngine.Debug.Log ("array search time = "+sw.ElapsedMilliseconds.ToString()+" ms");

        listSearchtext.text = sw.ElapsedMilliseconds.ToString()+" ms";
        sw.Reset ();
    }

    public void onClick_DictionarySearchTime(int key=111)
    {
        sw.Start ();
        bool containsKey = intDic.ContainsKey(key);
        sw.Stop ();
        UnityEngine.Debug.Log (containsKey);

        UnityEngine.Debug.Log ("array search time = "+sw.ElapsedMilliseconds.ToString()+" ms");
           
        dicSearchText.text = sw.ElapsedMilliseconds.ToString()+" ms";
        sw.Reset ();
    }
    public void onClick_DictionaryFindTime(int key=111)
    {
        sw.Start ();
        int value = intDic[key];
        sw.Stop ();

        UnityEngine.Debug.Log ("dic find time = "+sw.ElapsedMilliseconds.ToString()+" ms");

        dicFindText.text = sw.ElapsedMilliseconds.ToString()+" ms";
        sw.Reset ();
    }

    public void onClick_ListFindTime(int key=111)
    {
        sw.Start ();
        int valueindex = intList.FindIndex(i=> i==key);
        sw.Stop ();
        UnityEngine.Debug.Log ("array find time = "+sw.ElapsedMilliseconds.ToString()+" ms");

        listFindtext.text = sw.ElapsedMilliseconds.ToString()+" ms";
        sw.Reset ();
    }

 

That’s great. Now we create a new canvas, add above script on it and add few buttons to it.

Like this, Assign events from script.

Code is very simple. First, we created three collections Arrays, List and Dictionary. Insert some values(for simplicity we created integer types).

After That we create multiple on Click button Events for UI Buttons in Hierarchy.

For example:

We will assign event to button

and so on.

Earlier, we discussed that for performance tests we would be using stopwatch class object.

I hope we are done till now. Yes, we do not discussed about comparison of List, Array Dictionary and other collections. We will discuss these shortly.

Now click each button one by one and observe their execution times.

Like:

 

 

From above let us understand what we can get:

  • If Number of objects remains same through out the game logic we should avoid List or Dictionary. As arrays do the trick for us.
  • On the hand if number of objects keep changing during game we can have option of List and Dictionary.
  • A very important point to rise is that we noticed that foreach seems quit expensive in iterations. It effected the performance drastically bad.
  • Also Dictionary is very good in the case where we are interested in search and find objects.

Hey guys, We did, yes we . I know it may little confusing. But once you do it by hands things will be quite easy for you. Also remember by doing this experiment we do not claim stop using Collection Objects but you need to focus on your case and use specific collection as spotted in bullets above.

Enjoy! Do not forget to share with friends. Thanks.

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Follow by Email
Facebook
Facebook
Twitter