We wanted to have a visually appealing way to obscure some objects. So we decided on making a waterfall, but made out of spheres.
The first step to creating the waterfall was making use of object pooling. Object pooling allowed us to use a lot of different gameobjects, without affecting performance too much.
The first step is to create an ObjectPooler script, in that script we make a Pool class and give it the following variables:
public class Pool
{
public string tag;
public GameObject prefab;
public Transform poolContainer;
public int size;
}
After that we make a static ObjectPooler variable and give it the instance of this script in the awake function, we make this public so we can reference it on other scripts.
The ObjectPooler is going to keep track of multiple objectpools, so we need to use a for each loop that goes through every objectpool. After that we instantiate the objects we want to pool and set them inactive.
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 storedObject = Instantiate(pool.prefab);
storedObject.transform.parent = pool.poolContainer;
storedObject.name = pool.prefab.name;
storedObject.SetActive(false);
objectPool.Enqueue(storedObject);
}
poolDictionary.Add(pool.tag, objectPool);
}
}
When we want to use an object from the pool we call the following public function:
public GameObject SpawnFromPool(string poolTag, Vector3 position, Quaternion rotation, Transform parent)
{
if (!poolDictionary.ContainsKey(poolTag))
{
Debug.LogError("Pool with tag " + poolTag + " doesn't exist!");
return null;
}
GameObject objectToSpawn = poolDictionary[poolTag].Dequeue();
objectToSpawn.SetActive(true);
objectToSpawn.transform.position = position;
objectToSpawn.transform.rotation = rotation;
if (parent != null)
{
objectToSpawn.transform.SetParent(parent);
}
IPooledObject pooledObject = objectToSpawn.GetComponent<IPooledObject>();
if(pooledObject != null)
{
pooledObject.OnObjectSpawn();
}
poolDictionary[poolTag].Enqueue(objectToSpawn); // Requeue the object after you start using it
return objectToSpawn;
}
In this function it's important that the spawned object has an OnObjectSpawn function, we make sure that it has one by making the poolObject an IPooledObject. IPooledObject is an interface where we require the object to have an OnObjectSpawn function.
The last thing that we need to do is add a random velocity to the waterfall spheres and make it easy to be influenced by the inspector. I had a bit of help from Tirso with this. Here's the waterfall script:
private void FixedUpdate()
{
for (int i = 0; i < spawnRate; i++)
{
float xOffset = Random.Range(minPosX, maxPosX);
Vector3 rotatedXOffset = new Vector3(xOffset, 0, 0);
rotatedXOffset = transform.rotation * rotatedXOffset;
Vector3 position = transform.position + rotatedXOffset;
objectPooler.SpawnFromPool("Waterfall", position, transform.rotation, transform);
}
}