Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

is there a point in recycling value types unity

I found article stating that recycling and reusing variables is good practice in unity. So I adopted it. But one thing not clear : does this apply to value type variables (integers, vectors)?

is there a point i using this:

int x;
Vector3 v;
void functionCalledVeryOften(){
   x=SomeCalculation();
   v=SomeCalc();
   //do something with x and v
}

instead of this:

void functionCalledVeryOften(){
   int x=SomeCalculation();
   Vector3 v=SomeCalc();
   //do something with x and v
}
like image 403
ShoulO Avatar asked Oct 26 '16 03:10

ShoulO


2 Answers

This is fairly dependent on what you wish to do with this object.

Lets take your first example, say we would want to access the variables x & v from a second function functionCalledEveryOnceSoOften() This function won't need any overloads to pass the variables, and can just directly access the variables in the instance of the class.

With the second example, if we wanted to do the same thing. We would have to call functionCalledEveryOnceSoOften(int, vector3) As the function would not have direct access to the variables.

In unity it is often the case that a function will need to use the same values as another function, all though they might not always be called in chain's. To accommodate this in your 2nd example, we would have to add if statements inside our function to filter this out.

In your first example however, we could use these variables without a issue. This is one of the reasons it is often advised to do so.

As per the performance, in your 2nd example the variable is stored in the stack as opposed to the heap, because it is defined within the confines of a method which will get destroyed once the method ends executing. So the variable's memory usage is not really a concern. There might be a small overhead for the repeated creation and destruction, but this should be insignificant.

In your first example you will store the variable on the heap, as it is defined within the scope of the class, it will only be destroyed along with the class, and created on it's instantiation. This means that memory might be used over longer periods of time, but there will be no overhead for creating/destroying the variable. This also is usually insignificant.

All together, unless you are instantiating thousands of these objects, accessing the variables in rapid succession you will most likely not notice a lot of difference in performance.

The biggest difference will most likely be the way code is written. For better, or for worse.

like image 30
MX D Avatar answered Sep 26 '22 14:09

MX D


Is there a point in recycling value types unity

Yes, some datatypes not all.

does this apply to value type variables (integers, vectors)?

No.

It depends on the variable type.

This does not apply to int, double, float, bool, Vector3 and Vector2 and other similar datatypes. It does not even apply to string because already, string cannot be re-used in C#. strings are immutable.

In-fact, using int from a local variable, lets say in a while loop is faster than using int declared as global.

*Examples of when you should declare variable once and re-use it or in your own words, recycle or re-use variables in Unity*.

Arrays:

If a function contains array and that function is often called.

void functionCalledVeryOften()
{
    float[] playerLives = new float[5]; //This is bad because it allocates memory each time it is called
    for (int i = 0; i < playerLives.Length; i++)
    {
        playerLives[i] = UnityEngine.Random.Range(0f,5f);
    }
}

This allocates memory each time and can be solved by making the array global and initializing it outside the function once. You can create a simple function that resets the data in the array into 0.

float[] playerLives = new float[5]; 
void functionCalledVeryOften()
{
    for (int i = 0; i < playerLives.Length; i++)
    {
        playerLives[i] = UnityEngine.Random.Range(0f,5f);
    }
}

Creating new Objects:

Creating new Objects takes resources and can cause problems on mobile devices. This depends on how often you do this.

The code below creates a GameObject (bullet) then attaches Rigidbody to it and then shoots it.This happens every frame while space bar is held down and finally destroys the bullet 10 seconds later.

void functionCalledVeryOften()
{
    if (Input.GetKey(KeyCode.Space))
    {
        //Create new Bullet each time
        GameObject myObject = new GameObject("bullet");
        Rigidbody bullet = myObject.AddComponent<Rigidbody>() as Rigidbody;
        //Shoot Bullet
        bullet.velocity = transform.forward * 50;
        Destroy(myObject);
    }
}

The code above is bad as it allocates memory each time new GameObject is created and when the GameObject is destroyed, it will also trigger garbage collector. This can slow down and cause hiccups in your game.

The solution to the above code is Object pooling. You can learn more about it here: Object Pooling tutorial from Unity

Example of simple fix for this with a global variable:

List<GameObject> reUsableBullets;
int toUseIndex = 0;

void Start()
{
    intitOnce();
}

//Call this function once to create bullets
void intitOnce()
{
    reUsableBullets = new List<GameObject>();

    //Create 20 bullets then store the reference to a global variable for re-usal
    for (int i = 0; i < 20; i++)
    {
        reUsableBullets[i] = new GameObject("bullet");
        reUsableBullets[i].AddComponent<Rigidbody>();
        reUsableBullets[i].SetActive(false);
    }
}

void functionCalledVeryOften()
{
    if (Input.GetKey(KeyCode.Space))
    {
        //Re-use old bullet
        reUsableBullets[toUseIndex].SetActive(true); 
        Rigidbody tempRgb = reUsableBullets[toUseIndex].GetComponent<Rigidbody>();

        tempRgb.velocity = transform.forward * 50;
        toUseIndex++;

        //reset counter
        if (toUseIndex == reUsableBullets.Count - 1)
        {
            toUseIndex = 0;
        }
    }
}

So basically, you create an Object inside a function before Game begins, then store the reference in a global variable. You will then re-use that Object you created in the function since its reference is held in a global variable.

Instantiate:

The Instantiate function is used to create of copy of a prefab. The code below will instantiate a bullet then shoots it every frame while space bar is held down and finally destroys it 10 seconds later.

public GameObject bulletPrefab;
void functionCalledVeryOften()
{
    if (Input.GetKey(KeyCode.Space))
    {
        //Create new Bullet each time
        Rigidbody bullet = Instantiate(bulletPrefab, new Vector3(0, 0, 0), Quaternion.identity) as Rigidbody; 
        //Shoot Bullet
        bullet.velocity = transform.forward * 50;
        Destroy(myObject,10f);
    }
}

The code above is bad as it allocates memory depending on how many components is attached to the bullet prefab and how much child GameObject is under it. The solution is also use Object Pooling. Instantiate the GameObject in a function, store the reference in a global variable then re-use them. The solution is the-same with the solution above.

In conclusion, the example code in your question does not apply this.

You can learn more about Memory Management in Unity here.

like image 83
Programmer Avatar answered Sep 22 '22 14:09

Programmer