0
\$\begingroup\$

I created a little pool in order to better manage my enemies, to which, an enemySpawner object calls to retrieve a clone and show it on screen

public class ObjectPool : MonoBehaviour
{
    public static ObjectPool current;
    public GameObject objectForPool;
    public int poolAmmount = 20;
    public bool growth = true;

    List<GameObject> objectsForPool;

    void Awake()
    {
        current = this;    
    }

    // Use this for initialization
    void Start ()
    {
        objectsForPool = new List<GameObject>();

        for (int i = 0; i < poolAmmount; i++)
        {
            GameObject obj = Instantiate(objectForPool);
            obj.SetActive(false);
            objectsForPool.Add(obj);
        }
    }

    public GameObject GetPooledObject()
    {
        for (int i = 0; i < objectsForPool.Count; i++)
        {
            if (!objectsForPool[i].activeInHierarchy)
            {
                return objectsForPool[i];
            }
        }
        if (growth)
        {
            GameObject obj = Instantiate(objectForPool);            
            objectsForPool.Add(obj);
            return obj;
        }
        return null;
    }

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

    }
}

The call(EnemySpawner update)

void Update ()
{
    transform.position = new Vector3(transform.position.x + (speed * Time.deltaTime), 0, transform.position.z);
    if (transform.position.x <= boundary.xMin || transform.position.x >= boundary.xMax)
        speed *= -1;

    if (Time.time > nextSpawn)
    {
        nextSpawn = Time.time + spawnRate;

        GameObject clone = GetComponent<ObjectPool>().GetPooledObject();
        if (clone == null || clone.activeInHierarchy) return;
        clone.GetComponent<EnemyMovement>().SetPlayerShip(playerShip);
        clone.transform.position = transform.position;
        clone.transform.rotation = transform.rotation;
        clone.GetComponent<Health>().RestoreHealth();
        clone.SetActive(true);
    }
}

The problem here is, that my enemies are being deactivated on mid trajectory

https://youtu.be/ZGHC6wwGX1E

I know my issue is in my pooling, but I can't figure out what I'm doing wrong

\$\endgroup\$
  • \$\begingroup\$ It doesn't look like we have the information to reproduce or solve your problem here, because there's nowhere that the objects are being SetActive(false) after start, or Destroy()ed - can you search for places where that happens in your code and verify when it occurs? \$\endgroup\$ – DMGregory Jun 29 at 13:22
  • \$\begingroup\$ Ok, Finally figured out why this was happening. Stupid me had a 2 seconds live span of the object before the kill script is called. Forgot to set it that object are deactivated either by being killed of colliding with the kill box \$\endgroup\$ – CJLopez Jul 1 at 23:49
  • \$\begingroup\$ Post your solution as an answer then. \$\endgroup\$ – DMGregory Jul 2 at 0:10
  • \$\begingroup\$ Don't know if it's much of a solution, but, will do \$\endgroup\$ – CJLopez Jul 2 at 0:32
0
\$\begingroup\$

Well, finally realized my mistake

I followed Unity tutorial on object pooling

https://unity3d.com/es/learn/tutorials/topics/scripting/object-pooling

And, event though it works wonders on bullets, not so much on enemies.

I'm pooling the enemies, just, trying to keep a good memory management from the begginning, and every object pooled had this killScript

public class KillBox : MonoBehaviour
{    

    void OnEnable() => Invoke("Destroy", 2f);

    void Destroy() => gameObject.SetActive(false);

    private void OnDisable() => CancelInvoke();

}

This is the only place the SetActive(false) is ever called, so your mention of looking for this piece of code made me realize that, this is invoked 2 seconds after the object is pooled and activated. Changing this from 2 to 10 made that the enemies never dissapeared... like, never, and I had a kill box to set them innactive when reached, but the killbox logic wasn't ther, so I just needed to adjust this

public class KillBox : MonoBehaviour
{
    void OnTriggerExit(Collider other)
    {
        switch (other.gameObject.name)
        {
            case "Bullet":
                Debug.Log("A bullet reached the killbox");
                other.gameObject.transform.parent.gameObject.SetActive(false);
                break;
            case "Enemy(Clone)":
                Debug.Log("An Enemy reached the killbox");
                other.gameObject.SetActive(false);
                break;
            default:
                Debug.Log($"{other.gameObject.name} reached the killbox");
                break;
        }
    }
}

This way, enemies are respawned whenever they are inactive, either by the killBox, or when hit by a bullet

\$\endgroup\$
0
\$\begingroup\$

I could not read all your post, but I think just call SetActive(false) is not good idea. PooledObject have to be return to pool for reusing.

I love this site. I also recommend to read this. If you don't have time, see ObjectPool, PooledObject class only:)

\$\endgroup\$
  • \$\begingroup\$ Their code never removes the object from the pool, it just treats active objects as ineligible for use as new spawns. \$\endgroup\$ – DMGregory Jul 2 at 16:36
  • \$\begingroup\$ I believe, given you didn't read all my post, it's why you didn't understood the logic. Setting them as innactive its just that, they are no longer active, but still live in memory, ready to be reused and respawned, without needing to flesh more memory \$\endgroup\$ – CJLopez Jul 2 at 18:34
  • \$\begingroup\$ I'm just want to show you more about ObjectPool. If you gonna be change objectpool list management code, you don't need more GetPooledObject loop(for find inactive object). \$\endgroup\$ – Shin Dongho Jul 3 at 1:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.