Search Unity

Object pooling multiple prefabs randomly in a line

Discussion in 'Scripting' started by Zakkary19, May 2, 2019.

  1. Zakkary19

    Zakkary19

    Joined:
    Jan 4, 2016
    Posts:
    5
    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
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class TileManager : MonoBehaviour {
    6.  
    7.     //Tile Variables
    8.     public GameObject[] tilePrefabs;
    9.  
    10.     public static Transform playerTransform;
    11.     private float spawnZ = -13.0f;
    12.     private float tileLength = 13.0f;
    13.     private float safeZone = 12.0f;
    14.     private int amnTilesOnScreen = 4;
    15.     private int lastPrefabIndex = 0;
    16.  
    17.     public List<GameObject> activeTiles;
    18.  
    19.     // Use this for initialization
    20.     private void Start () {
    21.         activeTiles = new List<GameObject>();
    22.         playerTransform = GameObject.FindGameObjectWithTag("Player").transform;
    23.  
    24.         for (int i = 0; i < amnTilesOnScreen; i++)
    25.         {
    26.             if (i < 2)
    27.                 SpawnTile(0);
    28.             else
    29.                 SpawnTile();
    30.         }
    31.     }
    32.  
    33.     // Update is called once per frame
    34.     private void Update () {
    35.         if (playerTransform.position.z - safeZone > (spawnZ - amnTilesOnScreen * tileLength))
    36.         {
    37.             SpawnTile();
    38.             DeleteTile();
    39.         }
    40.     }
    41.  
    42.     private void SpawnTile(int prefabIndex = -1)
    43.     {
    44.         GameObject go;
    45.         if (prefabIndex == -1)
    46.             go = Instantiate(tilePrefabs[RandomTilePrefabIndex()]) as GameObject;
    47.         else
    48.             go = Instantiate(tilePrefabs[prefabIndex])as GameObject;
    49.  
    50.         go.transform.SetParent(transform);
    51.         go.transform.position = Vector3.forward * spawnZ;
    52.         spawnZ += tileLength;
    53.         activeTiles.Add(go);
    54.     }
    55.  
    56.     private void DeleteTile()
    57.     {
    58.  
    59.         Destroy(activeTiles[0]);
    60.         activeTiles.RemoveAt(0);
    61.     }
    62.  
    63.     private int RandomTilePrefabIndex()
    64.     {
    65.         if (tilePrefabs.Length <= 1)
    66.             return 0;
    67.  
    68.         int randomIndex = lastPrefabIndex;
    69.         while (randomIndex == lastPrefabIndex)
    70.         {
    71.             randomIndex = Random.Range(0, tilePrefabs.Length);
    72.         }
    73.  
    74.         lastPrefabIndex = randomIndex;
    75.         return randomIndex;
    76.     }
    77.  
    78.  
    79.     void DisableGameObject(GameObject go)
    80.     {
    81.         go.SetActive(false);
    82.     }
    83. }
    84.  

    ObjectPooler.cs
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class ObjectPooler : MonoBehaviour
    6. {
    7.     [System.Serializable]
    8.     public class Pool
    9.     {
    10.         public string tag;
    11.         public GameObject prefab;
    12.         public int size;
    13.     }
    14.  
    15.     #region Singleton
    16.  
    17.     public static ObjectPooler Instance;
    18.  
    19.     private void Awake()
    20.     {
    21.         Instance = this;
    22.     }
    23.  
    24.     #endregion
    25.  
    26.     public List<Pool> pools;
    27.     public Dictionary<string, Queue<GameObject>> poolDictionary;
    28.  
    29.     private void Start()
    30.     {
    31.         poolDictionary = new Dictionary<string, Queue<GameObject>>();
    32.  
    33.         foreach (Pool pool in pools)
    34.         {
    35.             Queue<GameObject> objectPool = new Queue<GameObject>();
    36.  
    37.             for (int i = 0; i < pool.size; i++)
    38.             {
    39.                 GameObject obj = Instantiate(pool.prefab);
    40.                 obj.SetActive(false);
    41.                 objectPool.Enqueue(obj);
    42.             }
    43.  
    44.             poolDictionary.Add(pool.tag, objectPool);
    45.         }
    46.  
    47.     }
    48.  
    49.     public GameObject SpawnFromPool(string tag, Vector3 position, Quaternion rotation)
    50.     {
    51.         if (!poolDictionary.ContainsKey(tag))
    52.         {
    53.             Debug.LogWarning("Pool with tag" + tag + " doesn't exist.");
    54.             return null;
    55.         }
    56.  
    57.      
    58.  
    59.         GameObject objectToSpawn = poolDictionary[tag].Dequeue();
    60.  
    61.         objectToSpawn.SetActive(true);
    62.         objectToSpawn.transform.position = position;
    63.         objectToSpawn.transform.rotation = rotation;
    64.  
    65.         poolDictionary[tag].Enqueue(objectToSpawn);
    66.  
    67.         return objectToSpawn;
    68.     }
    69.  
    70.  
    71. }
    72.  
     
  2. GroZZleR

    GroZZleR

    Joined:
    Feb 1, 2015
    Posts:
    3,201
    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.
     
  3. Zakkary19

    Zakkary19

    Joined:
    Jan 4, 2016
    Posts:
    5
    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.
     
  4. GroZZleR

    GroZZleR

    Joined:
    Feb 1, 2015
    Posts:
    3,201
    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.
     
    Zakkary19 and Joe-Censored like this.
  5. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    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.
     
    Zakkary19 and GroZZleR like this.
  6. Zakkary19

    Zakkary19

    Joined:
    Jan 4, 2016
    Posts:
    5
    Thank you both very much for your help!