- Home /
How to Use Object Pooling for a 3D Game?
So, for my project which is a Subway Surfers type game, I'm Instantiating when its clear I should be Pooling. My character moves along the Z Axis and I instantiate and then delete roughly 12 Obstacles every 5 seconds. My Draw Call is at a consistent 250 while my tris is at 144k.
How do I make a pooling system similar to my current system? Heres my current script. If possible, I want to make each tile seamlessly connect.
using System.Collections;
using UnityEngine;
using System.Collections.Generic;
public class TileManager : MonoBehaviour
{
public GameObject[] tilePrefabs;
private Transform playerTransform;
private float spawnZ = -10f;
private float tileLength = 27.7016f;
private float safeZone = 22.5f;
private int amnTilesOnScreen = 4;
private int lastPrefabIndex = 0;
private List<GameObject> activeTiles;
// Start is called before the first frame update
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[RandomPrefabIndex()]) 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 RandomPrefabIndex()
{
if (tilePrefabs.Length <= 1)
return 0;
int randomIndex = lastPrefabIndex;
while (randomIndex == lastPrefabIndex)
{
randomIndex = Random.Range(0, tilePrefabs.Length);
}
lastPrefabIndex = randomIndex;
return randomIndex;
}
}
Answer by revolute · Nov 29, 2019 at 03:07 AM
You would not want to destroy but just disable the tiles instantiated. And you have to keep track of what are pooled. Create a dictionary for the pool like this:
Dictionary<int, List<GameObject>> tilePool = new Dictionary<int,List<GameObject>>;
Then, in SpawnTile:
//make sure prefabIndex is set correctly.
if(!tilePool.ContainsKey(prefabIndex)) tilePool.Add(new List<GameObject>());
GameObject go = tilePool[prefabIndex].Find(x=>!x.activeSelf); // find disabled gameobject to reuse
if(go == null) {
go = Instantiate(tilePrefabs[prefabIndex]) as GameObject;
tilePool[prefabIndex].Add(go);
}
//set position for go and else
finally, in DeleteTile:
activeTiles[0].SetActive(false);//disable for reuse
activeTiles.RemoveAt(0);
Now you have a pool for tiles.
I've wrote this here so there may be typo errors but should be easy to fix.
Getting an error on this line on the word "Add".
How do I fix?
if (!tilePool.Contains$$anonymous$$ey(prefabIndex)) tilePool.Add(new List());
Assets\Scripts\Tile$$anonymous$$anager.cs(45,58): error CS7036: There is no argument given that corresponds to the required formal parameter 'value' of 'Dictionary>.Add(int, List)'