Search Unity

ObjectPooling and Movement Help

Discussion in 'Scripting' started by EmrenIng, Jan 16, 2019.

  1. EmrenIng

    EmrenIng

    Joined:
    Jun 21, 2018
    Posts:
    4
    I'm fairly new to unity/c# and I'm creating a small endless runner game where I use object pooling for the enemies. However I keep running into an issue where my enemies go back into the queue almost as soon as they are spawned. The image below shows the extent of their movement:

    I assume I have either somewhere defined how far they can go or I have failed to do so and I'm not sure how to go about doing it. Below are the scripts that may be relevant.
    ObjectPooler.cs
    Code (CSharp):
    1. public class ObjectPooler : MonoBehaviour
    2. {
    3.     public float speed;
    4.  
    5.     [System.Serializable]
    6.     public class Pool
    7.     {
    8.         public string tag;
    9.         public GameObject prefab;
    10.         public int size;
    11.     }
    12.  
    13.     public Pool poolt = new Pool();
    14.  
    15.     #region Singleton
    16.     public static ObjectPooler Instance;
    17.  
    18.     private void Awake()
    19.     {
    20.         Instance = this;
    21.     }
    22.     #endregion
    23.  
    24.     public List<Pool> pools;
    25.  
    26.     public Dictionary<string, Queue<GameObject>> poolDictionary;
    27.     // Start is called before the first frame update
    28.     void Start()
    29.     {
    30.         poolDictionary = new Dictionary<string, Queue<GameObject>>();
    31.  
    32.         foreach (Pool pool in pools)
    33.         {
    34.             Queue<GameObject> objectPool = new Queue<GameObject>();
    35.             for (int i = 0; i < pool.size; i++)
    36.             {
    37.                 GameObject obj = Instantiate(pool.prefab); // Creates an object by grabbing the prefab
    38.                 obj.SetActive(false);
    39.                 objectPool.Enqueue(obj);
    40.             }
    41.             poolDictionary.Add(pool.tag, objectPool);
    42.         }
    43.     }
    44.  
    45.     public GameObject SpawnFromPool (string tag, Vector2 position, Quaternion rotation)
    46.     {
    47.  
    48.         if (!poolDictionary.ContainsKey(tag))
    49.         {
    50.             Debug.LogWarning( tag + "Doesnt exsist");
    51.             return null;
    52.         }
    53.         GameObject objectToSpawn = poolDictionary[tag].Dequeue();
    54.  
    55.         objectToSpawn.transform.position = position;
    56.        
    57.  
    58.         poolDictionary[tag].Enqueue(objectToSpawn);
    59.  
    60.         return objectToSpawn;
    61.     }
    62. }
    CubeSpawner(MainSpawner)
    Code (CSharp):
    1. public class CubeSpawner : MonoBehaviour
    2. {
    3.     public GameObject[] enemyPatterns;
    4.  
    5.     ObjectPooler objectPooler;
    6.  
    7.     private float timeBtwSpawn;
    8.     public float startTimeBtwSpawn;
    9.     public float decreaseTime;
    10.  
    11.     public float minTime = 1f;
    12.  
    13.     void Start()
    14.     {
    15.         objectPooler = ObjectPooler.Instance;
    16.        
    17.     }
    18.  
    19.     // Update is called once per frame
    20.     void FixedUpdate()
    21.     {
    22.        
    23.         if (timeBtwSpawn <= 0)
    24.         {
    25.             int rand = Random.Range (0, enemyPatterns.Length);
    26.             timeBtwSpawn = startTimeBtwSpawn;
    27.             if (startTimeBtwSpawn > minTime)
    28.             {
    29.                 startTimeBtwSpawn -= decreaseTime;
    30.             }
    31.         } else
    32.         {
    33.             timeBtwSpawn -= Time.deltaTime;
    34.         }
    35.     }
    36. }
    37.  
    SpawnPoint
    Code (CSharp):
    1. public class SpawnPoint : MonoBehaviour
    2. {
    3.     //public GameObject enemy;
    4.  
    5.     public ObjectPooler objectPooler;
    6.     public Vector2 enposition;
    7.    
    8.  
    9.     // Start is called before the first frame update
    10.     void Start()
    11.     {
    12.         objectPooler = ObjectPooler.Instance;
    13.     }
    14.  
    15.     // Update is called once per frame
    16.     void Update()
    17.     {
    18.         objectPooler.SpawnFromPool("Cube", transform.position, Quaternion.identity).SetActive(true);
    19.         transform.position = new Vector2(transform.position.x, transform.position.y);
    20.     }
    21. }
    22.  
    TheCubeItself
    Code (CSharp):
    1. public class EnemyMovement : MonoBehaviour
    2. {
    3.     public float speed;
    4.  
    5.     public int damage = 1;
    6.  
    7.     // Update is called once per frame
    8.     void FixedUpdate()
    9.     {
    10.         transform.Translate(Vector3.left * speed * Time.deltaTime);
    11.     }
    12.  
    13.     void OnTriggerEnter2D(Collider2D other)
    14.     {
    15.         if(other.CompareTag("Player"))
    16.         {
    17.             other.GetComponent<PlayerMovement>().health -= damage;
    18.             Debug.Log(other.GetComponent<PlayerMovement>().health);
    19.             Destroy(gameObject);
    20.         }
    21.     }
    22. }
    Any help or direction would be greatly appreciated.
     
  2. doctorpangloss

    doctorpangloss

    Joined:
    Feb 20, 2013
    Posts:
    270
    Code (CSharp):
    1.  
    2.         GameObject objectToSpawn = poolDictionary[tag].Dequeue();
    3.         objectToSpawn.transform.position = position;
    4.      
    5.         poolDictionary[tag].Enqueue(objectToSpawn);
    6.  
    Well there's your problem :)

    Why are you enqueuing back the object you spawned? I know you're imagining that, "oh, it moved it to the top of the queue" or whatever, but that's not how object pools work. It's still in use! And then you destroy the game object, which makes it null in reference in the queue.

    Try starting with a working object pool implementation.
     
  3. wileyjerkins

    wileyjerkins

    Joined:
    Oct 13, 2017
    Posts:
    77
    I just rolled my own system for a space shooter. All I did was create an array of objects I wanted to pool, then wrote a script to instantiate as many of them as I would reasonably need and put them into separate lists according to name, then disable them all. Then, when I need one, just find a disabled one on the list, change its position to where you need it and enable it. Objects are disabled when they die (enemies) or hit or miss something (bullets that hit are disabled on collision, bullets that miss are disabled by a coroutine after 1 second). It is simple but works well.
     
  4. EmrenIng

    EmrenIng

    Joined:
    Jun 21, 2018
    Posts:
    4
    Thanks guys for your input! I think I'm dealing with things that are still a bit out of my knowledge atm I did end up redoing the script and did something similar to what wileyjerkins suggested.
     
  5. ihgyug

    ihgyug

    Joined:
    Aug 5, 2017
    Posts:
    194
    I don't know your project, but instead of disactivating the bullets after 1 second (which could lead to strange behaviour and restrictions, such as you can't have slow bullets because they would disappear before reaching your player or bullets could disappear while still on screen), you could use OnBecameInvisible(), and just set them unactive there.