0

I'm building a game in Unity3D and I am trying to reuse GameObjects by enabling and disabling them rather than instantiating and destroying them.

I have 10 springs in a GameObject array and every time I use a spring I want to take it from the first element in the array, shifting all of the remaining elements of that array up, then move the first Object to the last index in the array.

Programmer
  • 121,791
  • 22
  • 236
  • 328
LooMeenin
  • 818
  • 3
  • 17
  • 33
  • 1
    Why not use a queue where disabled elements are added and, when needed, you dequeue from it to get a previously disabled instance that only needs to be re-enabled. Why an array? – code_dredd May 30 '16 at 00:46
  • @ray - Not sure, just thought it might have an operation to do exactly what I'm trying to do! Never used a queue before. – LooMeenin May 30 '16 at 00:48
  • 1
    @LooMeenin: You should check the docs to see whether a class offers the operations you're looking for before trying to write code only to find out that's not the case. If you've never used a queue before (which is a basic data structure), you might need to get a better understanding of some fundamentals before diving into, or while you learn about, game programming. – code_dredd May 30 '16 at 00:51

1 Answers1

2

This is called Object Pooling. You do not need to remove array from first or last to do this. There are many ways to archive this in Unity.

Method 1 (Recommended):

Even though that works, it unnecessary and inefficient to move the Objects in the array. You can have an index that moves around. It starts from 0 and each time you request an Object, you increment it by one. If the index equals to Array.Length - 1, reset index back to 0.

public class ArrayObjectPooling
{
    int amount = 10;
    GameObject[] objArray;
    int currentIndex = 0;

    public ArrayObjectPooling(GameObject objPrefab, string name, int count)
    {
        amount = count;
        objArray = new GameObject[amount];

        for (int i = 0; i < objArray.Length; i++)
        {
            objArray[i] = UnityEngine.Object.Instantiate(objPrefab, Vector3.zero, Quaternion.identity);
            objArray[i].SetActive(false);
            objArray[i].name = name + " #" + i;
        }
    }

    //Returns available GameObject
    public GameObject getAvailabeObject()
    {
        //Get the first GameObject
        GameObject firstObject = objArray[currentIndex];

        //Move the pointer down by 1
        shiftDown();

        return firstObject;
    }

    //Returns How much GameObject in the Array
    public int getAmount()
    {
        return amount;
    }

    //Moves the current currentIndex GameObject Down by 1
    private void shiftDown()
    {
        if (currentIndex < objArray.Length - 1)
        {
            currentIndex++;
        }
        else
        {
            //Reached the end. Reset to 0
            currentIndex = 0;
        }
    }
}

USAGE:

public GameObject prefab;

void Start()
{
    ArrayObjectPooling arrayPool = new ArrayObjectPooling(prefab, "Springs", 10);
    GameObject myObj = arrayPool.getAvailabeObject();
}

Method 2:

List is enough to do this if the pool is small. Please take a look at Unity's official tutorial for Object Pooling implemented this. It is unnecessary to post the code here.

You simply disable the GameObject in the List to recycle it. Next time you need a new one, loop over the List and return the first disabled GameObject in the List. If it is enabled, that means that it is still in use.

If no disabled GameObject is found in the List, then you can Instantiate a new one, add it to the list and then return it. This is the easiest way of doing this. Just watch the Unity tutorial for more information.


Method 3:

Use Queue or Stack. You can queue and enqueue or push/pop the Objects from the pool. There are many implementation out there if you do a simple reseach-search on this.


Method 4:

This is only mentioned because this was your original question about how to shift objects up in an array and then put the first value in the last index of the array. You should not not use this. It is only here just to show that it can be done.

public class ArrayObjectPooling
{
    int amount = 10;
    public GameObject[] objArray;

    public ArrayObjectPooling(GameObject objPrefab, string name, int count)
    {
        amount = count;
        objArray = new GameObject[amount];

        for (int i = 0; i < objArray.Length; i++)
        {
            objArray[i] = UnityEngine.Object.Instantiate(objPrefab, Vector3.zero, Quaternion.identity);
            objArray[i].SetActive(false);
            objArray[i].name = name + " #" + i;
        }
    }

    //Returns available GameObject
    public GameObject getAvailabeObject()
    {
        //Get the first GameObject
        GameObject firstObject = objArray[0];

        //Move everything Up by one
        shiftUp();

        return firstObject;
    }

    //Returns How much GameObject in the Array
    public int getAmount()
    {
        return amount;
    }

    //Moves the GameObject Up by 1 and moves the first one to the last one
    private void shiftUp()
    {
        //Get first GameObject
        GameObject firstObject = objArray[0];

        //Shift the GameObjects Up by 1
        Array.Copy(objArray, 1, objArray, 0, objArray.Length - 1);

        //(First one is left out)Now Put first GameObject to the Last one
        objArray[objArray.Length - 1] = firstObject;
    }
}

USAGE:

public GameObject prefab;

void Start()
{
    ArrayObjectPooling arrayPool = new ArrayObjectPooling(prefab, "Springs", 3);
    GameObject myObj = arrayPool.getAvailabeObject();
}
Programmer
  • 121,791
  • 22
  • 236
  • 328
  • Yeah thought about that but didn't want to check if the GameObjects are enabled. Thought there might be an operation in some type of array or list that just throws the GameObject to the end of the array/list. That way I can just use the first GameObject in the array every time with no check – LooMeenin May 30 '16 at 01:07
  • I've seen that tutorial before and I've used object pooling in the past but I thought for this scenario I would prefer to use an array or list of some sort that has the operation I described. If there is no operation like that then I will figure something else out. – LooMeenin May 30 '16 at 01:12
  • @LooMeenin **I am trying to reuse GameObjects by enabling and disabling them rather than instantiating and destroying them** now you are saying you do not want to check if they are enabled/disabled? Why even bother enabling/disabling them in the first place? You want to use array, what if you need more than 10 springs? Are they guaranteed to be 10 forever during the game? – Programmer May 30 '16 at 01:18
  • They are guaranteed to be 10 forever during the game. I bother to enable and disable them because of the performance tax of keeping them enabled when not being used. – LooMeenin May 30 '16 at 01:20
  • Yes I can just check to see if the GameObject is enabled before using it but there are more springs enabled than disabled at most times during gameplay so I dont want to loop through several just to find a disabled one if I can just use the first one in the array every time like i said before. – LooMeenin May 30 '16 at 01:27
  • @LooMeenin Look at my updated answer. That's exactly what you are looking for. Each time you return an available spring, the first one is moved to the last. – Programmer May 30 '16 at 02:20
  • @PeterDuniho I actually use Object pooling but not this solution. *I use index on my object pooling class*. OP asked for moving objects and moving the first to the last in an array so that's exactly what I provided. The question is not about the most efficient way to do this. You think that necessary to post that too? – Programmer Mar 06 '17 at 23:34
  • Also, remember that this is not the only solution in my answer. My initial solution is actually to disable the gameobject when you are done using it then search for a disable gameobject when you need new object from the pool. – Programmer Mar 06 '17 at 23:37
  • Looks much better. Thank you. – Peter Duniho Mar 07 '17 at 01:27
  • You are welcome! – Programmer Mar 07 '17 at 01:28