DEV Community

Andy
Andy

Posted on

Unity: Comparison of performance cost between "GameObject.Find" and direct referencing

When I was developing Unity games, I had learned that GameObject.Find is slow once the size of object becomes bigger. Also, many game developers suggested against using such method, as it not only slows down the program, but also impacts the overall maintainability of the code. But I have never get a chance to quantify how slow will the game become if we exploit the usage of GameObject.Find. Therefore, it is a good time to perform an experiment on these two methods. In this article, I will do a very simple experiment on the following methods. All of these methods perform the same action: Getting a reference to a game object.

  • GameObject.Find
  • Set up the public variable in the script, then drag the other game object to the reference box in Unity Editor.

The development environment I am on is 2019.3.7.f1. I will perform the scripting in this experiment using C#. Here is how I set up the structure of the experiment:

  • Independent variable: The method of accessing the reference to a Cube game object
  • Dependent variable: The time elapsed after scanning through all the Cube game object using the given method
  • The CPU, RAM usage, and other game objects (Main Camera, Directional Light) are controlled and won't change.

Getting Started

Firstly, I created a new Unity project, as usual.
Alt Text

My brand new project looked as empty as this:
Alt Text

Testing the performance of direct referencing

To start testing, it's time to write some scripts -- under Assets folder, I created scripts directory and then added a new script, as you can see from the screen shot below:
Alt Text

Here is how the test is implemented. To test the performance of direct referencing an object in Editor, we firstly create 10,000 GameObjects using the following script:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[ExecuteInEditMode]
public class FindTest : MonoBehaviour
{
    private static int size = 10000;
    public GameObject[] cubes = new GameObject[size];
    void OnEnable()
    {
        cubes = new GameObject[size];
        for (int i = 0; i < size; i++){
            GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
            cube.name = i.ToString();
            cubes[i] = cube;
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

To use this script, simply create an empty game object. Then, on the right side, search for the Create script. Once you load the Create script, 10,000 cubes will pop up in the editor, and they are all binded to the cubes array in Create class.
Once we finished creating these GameObjects, the editor will look like this:
Alt Text

Since each cube has a BoxCollider component, our goal is to turn off the BoxCollider of all the components. We will measure how long does this action take.

We use the following script to perform the action, which is modified based upon the previous script: We removed the procedure for creating the cubes, and replaced them with cubes[i].GetComponent<BoxCollider>().enabled = false.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Create : MonoBehaviour
{
    private static int size = 10000;
    public GameObject[] cubes;

    void OnEnable()
    {
        for (int i = 0; i < size; i++){
            cubes[i].GetComponent<BoxCollider>().enabled = false;
        }
        Debug.Log(Time.realtimeSinceStartup);
    }
}
Enter fullscreen mode Exit fullscreen mode

Once Unity finishes the action, the time elapsed (in seconds) will be sent to the console. We perform the same action 10 times. The console will then look like this, if we turn off clear on play and all other options. The console will collect all the data once we finish the experiment.

Alt Text

We extracted the dataset into a spreadsheet.
The following table shows the result after this first experiment:
Alt Text

Now, let us move on to the second test, to see how does GameObject.Find() performs.

Testing GameObject.Find()

Now let us test the performance of GameObject.Find(). We can use the testing scripts we developed previously, with some slight modifications. In fact, we only modified one line -- changing from cubes[i].GetComponent<BoxCollider>().enabled = false; to GameObject.Find(i.ToString()).GetComponent<BoxCollider>().enabled = false;. This will change the way we access to the Cube objects.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Create : MonoBehaviour
{
    private static int size = 10000;
    public GameObject[] cubes;

    void OnEnable()
    {
        for (int i = 0; i < size; i++){
            GameObject.Find(i.ToString()).GetComponent<BoxCollider>().enabled = false; // Modified line
        }
        Debug.Log(Time.realtimeSinceStartup);
    }
}
Enter fullscreen mode Exit fullscreen mode

After performing the test 10 times (same as before), we recorded the following data -- indeed, as we can see, GameObject.Find() took longer in accessing all the game objects and turn their BoxColliders off.
Alt Text

Testing on a smaller number of game objects

We have seen that GameObject.Find() significantly lags behind when there is a large number of GameObjects in the scene. But what if we change the number of objects into a smaller one, e.g. 100? Let's do the same experiment with the smaller number.
Alt Text
Alt Text

We can see from the figure above there isn't a huge time difference between these two methods if we reduce the number of game objects in the experiment -- GameObject.Find even has a tiny edge over direct referencing in this smaller experiment. After gathering all the data, we produced the following figure, whereas each bar represents the average time of using the corresponding method:
Alt Text

Conclusion

In conclusion, we can discover that GameObject.Find has worse performance comparing to direct referencing in the experiment. This is potentially due to the fact that GameObject.Find needs to linearly find the object with corresponding name, whereas the direct referencing method does not need to perform linear search. Overall, if one doesn't really need to use GameObject.Find, it should be avoided.

However, in this experiment, we have only explored two of the many methods for referencing a game object in Unity. There are many methods that we can also include in this experiment. For instance, we have not tried FindObjectOfType and FindGameObjectsWithTag yet. These are the methods that we can include in the future experiments.

Top comments (1)

Collapse
 
gitjohnn profile image
Jonathan Gonzalez

Really interesting! Keep up the awesome experiements!