I have created a generic object pooling script which I intend to reuse. From a design standpoint, I thought it would be best to go with a Pool class, which can be inherited from, and an IPoolable interface, which specifies the contract that poolable objects would have to fulfill. Here are the relevant parts:
public interface IPoolable {
bool IsIncarnate();
void Incarnate(Vector3 position, Quaternion rotation, Vector3 scale); //Called when the object is checked out from the pool
void Relinquish(); //Called to return the object to the pool.
}
and
public class Pool : MonoBehaviour {
public int count = 256;
public IPoolable pooledObj;
public List<IPoolable> allObj;
//snip some irrelevant stuff
protected virtual void Start() {
allObj = new List<IPoolable>(count);
InstantiatePool();
}
protected virtual void InstantiatePool() {
for (int i = 0; i < count; i++) {
allObj.Add((IPoolable)Instantiate(pooledObj));
allObj*.Relinquish();*
-
}*
-
}*
-
public IPoolable GetNext() {*
-
IPoolable next = allObj.Find(x => !x.IsIncarnate());*
-
//snip behavior of what to do when full*
-
return next;*
-
}*
}
The issue I was having was with this line:
allObj.Add((IPoolable)Instantiate(pooledObj));
The problem is that Instantiate requires a UnityEngine.Object. IPoolable is an interface, so it seems that, even though it is always attached to an Object, which can be instantiated, the compiler doesn’t know that.
I did come up with a solution, which was to change IPoolable from an interface into an abstract class, called Poolable:
public abstract class Poolable : MonoBehaviour {
-
public virtual bool IsIncarnate { get { return gameObject.activeInHierarchy; } }*
-
public abstract void Incarnate(Vector3 position, Quaternion rotation, Vector3 scale); //Called when the object is checked out from the pool*
-
public virtual void Relinquish() { //Called to return the object to the pool.*
-
gameObject.SetActive(false);*
-
}*
}
Because this class inherits from MonoBehavior, it fulfills the condition that Instantiate must accept an Object argument. However, from a design perspective this feels wrong - it seems to me that I really only want to specify a contract in Poolable, so I should be using an interface. What would happen, for example, if I need an object to be both poolable and inherit from another MonoBehavior? This solution would make that impossible, because only one class can be inherited from - although multiple interfaces can be implemented.
So my question - is there a way to make that problem line work? A way that I can instantiate the object even though I have a handle on it by the IPoolable interface?