Object pooling multiple prefabs randomly in a line

So I am making an endless runner but was using a way that is not very good for performance, as you can see in the TileManager.cs script. That script works perfectly fine, it just causes stutters during gameplay on mobile. So then I discovered Object Pooling and stumbled across this Brackeys tutorial (

).

However I am not sure how to make what I was doing in TileManager.cs compatible with object pooling. All the object pooler does right now is spawn my prefabs in the same spot in a deactivated state. I would like if somehow I could pick a random object out of the pool and spawn in front of the last spawned object (I am sure you understand how an endless runner works). Thanks in advance for any help!

TileManager.cs

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

public class TileManager : MonoBehaviour {

    //Tile Variables
    public GameObject[] tilePrefabs;

    public static Transform playerTransform;
    private float spawnZ = -13.0f;
    private float tileLength = 13.0f;
    private float safeZone = 12.0f;
    private int amnTilesOnScreen = 4;
    private int lastPrefabIndex = 0;

    public List<GameObject> activeTiles;

    // Use this for initialization
    private void Start () {
        activeTiles = new List<GameObject>();
        playerTransform = GameObject.FindGameObjectWithTag("Player").transform;

        for (int i = 0; i < amnTilesOnScreen; i++)
        {
            if (i < 2)
                SpawnTile(0);
            else
                SpawnTile();
        }
    }
  
    // Update is called once per frame
    private void Update () {
        if (playerTransform.position.z - safeZone > (spawnZ - amnTilesOnScreen * tileLength))
        {
            SpawnTile();
            DeleteTile();
        }
    }

    private void SpawnTile(int prefabIndex = -1)
    {
        GameObject go;
        if (prefabIndex == -1)
            go = Instantiate(tilePrefabs[RandomTilePrefabIndex()]) as GameObject;
        else
            go = Instantiate(tilePrefabs[prefabIndex])as GameObject;

        go.transform.SetParent(transform);
        go.transform.position = Vector3.forward * spawnZ;
        spawnZ += tileLength;
        activeTiles.Add(go);
    }

    private void DeleteTile()
    {

        Destroy(activeTiles[0]);
        activeTiles.RemoveAt(0);
    }

    private int RandomTilePrefabIndex()
    {
        if (tilePrefabs.Length <= 1)
            return 0;

        int randomIndex = lastPrefabIndex;
        while (randomIndex == lastPrefabIndex)
        {
            randomIndex = Random.Range(0, tilePrefabs.Length);
        }

        lastPrefabIndex = randomIndex;
        return randomIndex;
    }


    void DisableGameObject(GameObject go)
    {
        go.SetActive(false);
    }
}

ObjectPooler.cs

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

public class ObjectPooler : MonoBehaviour
{
    [System.Serializable]
    public class Pool
    {
        public string tag;
        public GameObject prefab;
        public int size;
    }

    #region Singleton

    public static ObjectPooler Instance;

    private void Awake()
    {
        Instance = this;
    }

    #endregion

    public List<Pool> pools;
    public Dictionary<string, Queue<GameObject>> poolDictionary;

    private void Start()
    {
        poolDictionary = new Dictionary<string, Queue<GameObject>>();

        foreach (Pool pool in pools)
        {
            Queue<GameObject> objectPool = new Queue<GameObject>();

            for (int i = 0; i < pool.size; i++)
            {
                GameObject obj = Instantiate(pool.prefab);
                obj.SetActive(false);
                objectPool.Enqueue(obj);
            }

            poolDictionary.Add(pool.tag, objectPool);
        }

    }

    public GameObject SpawnFromPool(string tag, Vector3 position, Quaternion rotation)
    {
        if (!poolDictionary.ContainsKey(tag))
        {
            Debug.LogWarning("Pool with tag" + tag + " doesn't exist.");
            return null;
        }

      

        GameObject objectToSpawn = poolDictionary[tag].Dequeue();

        objectToSpawn.SetActive(true);
        objectToSpawn.transform.position = position;
        objectToSpawn.transform.rotation = rotation;

        poolDictionary[tag].Enqueue(objectToSpawn);

        return objectToSpawn;
    }


}

You need to replace your Instantiate calls in SpawnTile with objects you collect from the pool instead, and then position as normal. You can also just reposition tiles from behind the camera to in front of the camera and avoid using a “traditional” object pool entirely.

So you are saying that I could just edit TileManager and do away with the ObjectPooler script? If so, I am not exactly sure where I would set it to deactivate a prefab behind the camera then reactivate a random unactive prefab and place ahead of the camera. Sorry if this is something simple, I understand the concept of object pooling but I am not sure how to actually insert it into what I already have.

Thanks again.

It was just a suggestion – if you’re more comfortable using a pool, that’s fine, it is more straight forward. Simply replace all of your Instantiate/Destroy calls with calls to fetch/return an object from the pool. It should slide right in as a replacement.

2 Likes

The way an object pool generally works, is you never instantiate the object from the script which wants a new one. You request an object from your pool manager. It is the object pool manager’s responsibility for returning an unused object to the calling script, or instantiating one if the pool doesn’t contain an object available to return.

The same principal applies to destroying the object. Your scripts don’t destroy the object directly, then just return it to the pool. The pool manager script can be designed to destroy excess objects if you wish, or not, but the pool manager script is the only script which ever destroys a pooled object.

2 Likes

Thank you both very much for your help!