Object spawned from object pool ignores functions

That’s kind of the best way to describe my problem, I guess. I found a great object pool that was in JS and with help here I managed to convert it to C#. The pool works, it creates the pool for the specified amount of projectiles and spawns them in the heirarchy deactivated but only one object will be used.

The projectile is scripted to deactivate on collision and spawn a particle effect. The first time I fire a projectile, it does this as intended. But every time after that I fire, the projectile will ignore collisions and keep moving forward. Firing again will only reset that object’s position back to the scripted launch position, but it will still ignore collisions. If I fire the first projectile, and fire again while it is still moving, that projectile will just reset its position but still collide. It will not collide after.

Basically, a second projectile is never activated from the pool. It’s only resetting the first projectile. So, I’m a bit confused why it’s doing this. Four scripts are doing this, so I hope it’s not too much to read through and I greatly appreciate any help.

The object pooling scripts:

public class EasyObjectPool : MonoBehaviour {
	[System.Serializable]
	public class PoolInfo{
		[SerializeField]
		public string poolName;
		public GameObject prefab;
		public int poolSize;
		public bool canGrowPoolSize = true;
		
	}

	[System.Serializable]
	public class Pool{
		
		public List<PoolObject> list = new List<PoolObject>();
		public bool  canGrowPoolSize;
		
		public void  Add (PoolObject poolObject){
			list.Add(poolObject);
		}
		
		public int Count (){
			return list.Count;
		}
		
		
		public PoolObject ObjectAt ( int index  ){

			PoolObject result = null;
			if(index < list.Count) {
				result = list[index];
			}
			
			return result;
			
		}
	}
	static public EasyObjectPool instance ;

	[SerializeField]
	PoolInfo[] poolInfo = null;
	
	private Dictionary<string, Pool> poolDictionary  = new Dictionary<string, Pool>();

	
	void Start () {
		
		instance = this;
		
		CheckForDuplicatePoolNames();
		
		CreatePools();
		
	}
	
	private void CheckForDuplicatePoolNames() {
		
		for (int index = 0; index < poolInfo.Length; index++) {
			string poolName= poolInfo[index].poolName;
			if(poolName.Length == 0) {
				Debug.LogError(string.Format("Pool {0} does not have a name!",index));
			}
			for (int internalIndex = index + 1; internalIndex < poolInfo.Length; internalIndex++) {
				if(poolName == poolInfo[internalIndex].poolName) {
					Debug.LogError(string.Format("Pool {0} & {1} have the same name. Assign different names.", index, internalIndex));
				}
			}
		}
	}
	
	private void CreatePools() {
		
		foreach(PoolInfo currentPoolInfo in poolInfo){
			
			Pool pool = new Pool();
			pool.canGrowPoolSize = currentPoolInfo.canGrowPoolSize;
			
			for(int index = 0; index < currentPoolInfo.poolSize; index++) {
				//instantiate
				GameObject go = Instantiate(currentPoolInfo.prefab) as GameObject;
				PoolObject poolObject = go.GetComponent<PoolObject>();
				if(poolObject == null) {
					Debug.LogError("Prefab must have PoolObject script attached!: " + currentPoolInfo.poolName);
				} else {
					//set state
					poolObject.ReturnToPool();
					//add to pool
					pool.Add(poolObject);
				}
			}
			
			Debug.Log("Adding pool for: " + currentPoolInfo.poolName);
			poolDictionary[currentPoolInfo.poolName] = pool;
			
		}
	}
	
	public PoolObject GetObjectFromPool ( string poolName  ){
		PoolObject poolObject = null;
		
		if(poolDictionary.ContainsKey(poolName)) {
			Pool pool = poolDictionary[poolName];
			
			//get the available object
			for (int index = 0; index < pool.Count(); index++) {
				PoolObject currentObject = pool.ObjectAt(index);
				
				if(currentObject.AvailableForReuse()) {
					//found an available object in pool
					poolObject = currentObject;
					break;
				}
			}
			
			
			if(poolObject == null) {
				if(pool.canGrowPoolSize) {
					Debug.Log("Increasing pool size by 1: " + poolName);
					
					foreach (PoolInfo currentPoolInfo in poolInfo) {    
						
						if(poolName == currentPoolInfo.poolName) {
							
							GameObject go = Instantiate(currentPoolInfo.prefab) as GameObject;
							poolObject = go.GetComponent<PoolObject>();
							//set state
							poolObject.ReturnToPool();
							//add to pool
							pool.Add(poolObject);
							
							break;
							
						}
					}
				} else {
					Debug.LogWarning("No object available in pool. Consider setting canGrowPoolSize to true.: " + poolName);
				}
			}
			
		} else {
			Debug.LogError("Invalid pool name specified: " + poolName);
		}
		
		return poolObject;
	}
	
}

And:

public class PoolObject : MonoBehaviour {

	[HideInInspector]
	public bool availableForReuse = true;


	public void Activate () {

		availableForReuse = false;
		gameObject.SetActive(true);
	
	}
	

	public void ReturnToPool () {

		gameObject.SetActive(false);
		availableForReuse = true;

	
	}

	public bool AvailableForReuse () {
		//true when isAvailableForReuse & inactive in hierarchy

		return availableForReuse && (gameObject.activeInHierarchy == false);



	}
}

My shoot script:

public class ShootScript : MonoBehaviour {

	public PoolObject poolObject;

	private Transform myTransform;

	private Transform cameraTransform;

	private Vector3 launchPosition = new Vector3();

	public float fireRate = 0.2f;

	public float nextFire = 0;



	// Use this for initialization
	void Start () {
	
            string poolName= "Projectile";

		poolObject = EasyObjectPool.instance.GetObjectFromPool(poolName);



	}

	void OnEnable () {

		myTransform = transform;

		cameraTransform = myTransform.FindChild("BulletSpawn");
	}

	void Update () {


		if(Input.GetButton("Fire1") && Time.time > nextFire){

			nextFire = Time.time + fireRate;

			launchPosition = cameraTransform.TransformPoint(0, 0, 0.2f);

			poolObject.Activate();

			poolObject.transform.position = launchPosition;
			poolObject.transform.rotation = Quaternion.Euler(cameraTransform.eulerAngles.x + 90, myTransform.eulerAngles.y, 0);

		}
	
	}
}

Projectile script:

public class BulletScript : MonoBehaviour {

public GameObject hitEffect;

private Transform myTransform;

public float bulletSpeed = 0.1f;

private bool spent = false;

private RaycastHit hit;

public float rayRange = 1.5f;

// Use this for initialization
void OnEnable () {

	myTransform = transform;



}

// Update is called once per frame
void Update () {

	myTransform.Translate(Vector3.up * bulletSpeed * Time.deltaTime);

	if(Physics.Raycast(myTransform.position, myTransform.up, out hit, rayRange)&&
	   spent == false){

		if(hit.transform.tag == "Floor"){

			GameObject newHitEffect = (GameObject)Instantiate(hitEffect, hit.point, Quaternion.identity);

			Destroy(newHitEffect, 2);

			spent = true;

			GetComponent<PoolObject>().ReturnToPool();

		}

	}

}

}

Well, that’s a common problem you have to face when using an object pool. Since you reuse the same objects you have to implement something to reset the object into a state that it actually can be reused. Your BulletScript expects the “spent” variable to be false initially. However once the bullet hit something you set it to true and it will never by false again.

You can either set “spent” to false in OnEnable, or (what would be the more versatile approach) implement an “OnReset” callback which your pool manager invokes (via SendMessage) to reset the object in the pool when it is used / reused.

Ofcourse all scripts that are used on a pooled object has to be checked / changed to work with the pooling mechanics.

edit
Just saw you also misused the pool :wink:

You should use:

EasyObjectPool.instance.GetObjectFromPool(poolName);

instead of Instantiate and not just call it once in start. At the moment you take one object out of the pool in start and use it when you actually want to instantiate one object. After calling ReturnToPool the object reference shouldn’t be used anymore since it’s back in the pool. You have to call GetObjectFromPool again to get a new object from the pool (which might be the same you just returned).