Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by G_H_O_S_T · Mar 05, 2018 at 04:55 PM · lagspawning problemsspawnerframerate dropsobjectpool

Object Pooling Spawn,Unity slows down when object pooling,Unity Slows down when Object Pooling

I'm building a Survival FPS and using Object Pooling to spawn and remove NPC's. So far I have only added 2 types of enemies. 1) Fantasy Skeleton 2) Strong Knight both from the Asset Store. When I run the game it seems to be working fine with the Skeleton no matter how many of them I spawn say 20 or 30 but the same way if I try to spawn a Knight it gets all slow and laggy after 3 spawn from the various spawn points. I'm really left puzzled here as Object Pooling is supposed to reduce the computational cost for the game. Is there something I'm overlooking here? or what are the limitations of object pooling?

SideNote: The Knight does have a set of complex animation state machines where are the skeleton only has four states of animation. Does this affect object pooling?

Thanks -N,I'm building a Survival FPS and using Object Pooling to spawn and remove NPC's. So far I have only added 2 types of enemies. 1) Fantasy Skeleton 2) Strong Knight both from the Asset Store. When I run the game it seems to be working fine with the Skeleton no matter how many of them I spawn say 20 or 30 but the same way if I try to spawn a Knight it gets all slow and laggy after 3 spawn from the various spawn points. I'm really left puzzled here as Object Pooling is supposed to reduce the computational cost for the game. Is there something I'm overlooking here? or what are the limitations of object pooling?

SideNote: The Knight does have a set of complex animation state machines where are the skeleton only has four states of animation. Does this affect object pooling?

Thanks -N ,

Comment
Add comment · Show 1
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Pagefile · Mar 05, 2018 at 05:10 PM 0
Share

Does the lag only occur during spawning or does it continue after the knights spawn? If it's continuous it suggests something is going on with the knight. An easy way to test would be to put several of them in an empty scene without the object pooling and run it.

1 Reply

· Add your reply
  • Sort: 
avatar image
0

Answer by Xarbrough · Mar 05, 2018 at 05:54 PM

There's a couple of limitations I can think of:

  1. Unity's object creation and destruction is far less evil than people make it out to be. It could just be that it's faster to instantiate an object and destroy it than to retrieve it from the pool and initialize it. Especially when the amount of objects and frequency of use is low.

  2. What is your object pool code? Maybe you have an inefficient implementation.

  3. The bottleneck is typically object-initialization/resetting, e.g., SetActive may have a considerable overhead depending on how many children and components the GameObject has.

Show us your code, if you'd like some feedback. Other than that, I can share a few object pool implementations:


 using System;
 using System.Collections.Generic;
 using UnityEngine.Assertions;
 
 public class GenericPool<T>
 {
     private readonly Stack<T> m_Pool;
     private readonly HashSet<T> m_Active;
 
     private readonly Func<T> m_FuncCreate;
     private readonly Action<T> m_ActionGet;
     private readonly Action<T> m_ActionReturn;
 
     public GenericPool(Func<T> createFunction, Action<T> onGet, Action<T> onReturn, int capacity = 0)
     {
         Assert.IsNotNull(createFunction);
 
         m_Pool = new Stack<T>(capacity);
         m_Active = new HashSet<T>();
 
         m_FuncCreate = createFunction;
         m_ActionGet = onGet;
         m_ActionReturn = onReturn;
     }
 
     public void Prewarm(int capacity)
     {
         for (int i = 0; i < capacity; i++)
             Return(m_FuncCreate.Invoke());
     }
 
     public T Get()
     {
         T element;
 
         if (m_Pool.Count == 0)
             element = m_FuncCreate.Invoke();
         else
             element = m_Pool.Pop();
 
         if (m_ActionGet != null)
             m_ActionGet.Invoke(element);
 
         m_Active.Add(element);
         return element;
     }
 
     public void Return(T element)
     {
 #if DEBUG
         if (m_Pool.Contains(element))
             throw new InvalidOperationException("Element '" + element + "' already in pool.");
 #endif
 
         if (m_ActionReturn != null)
             m_ActionReturn.Invoke(element);
 
         m_Active.Remove(element);
         m_Pool.Push(element);
     }
 
     public void GatherAll()
     {
         foreach (T element in m_Active)
             Return(element);
     }
 
     public void ActionOnAll(Action<T> action)
     {
         foreach (T element in m_Active)
             action.Invoke(element);
     }
 }



 using UnityEngine;
 using System.Collections.Generic;
 
 namespace Demo
 {
     public class ObjectPool_A : EnemyFactory
     {
         public int startCount = 21;
 
         Stack<GameObject> instances = new Stack<GameObject>();
 
         void Start()
         {
             for (int i = 0; i < startCount; i++)
                 GrowPool();
         }
 
         void GrowPool()
         {
             GameObject instance = Instantiate(prefab);
             instance.SetActive(false);
             instances.Push(instance);
         }
 
         public override GameObject Spawn(Transform spawnPoint)
         {
             if (instances.Count < 1)
                 GrowPool();
 
             GameObject instance = instances.Pop();
             instance.transform.SetPositionAndRotation(spawnPoint.position, spawnPoint.rotation);
             instance.SetActive(true);
 
             return instance;
         }
 
         public override void Despawn(GameObject instance)
         {
             instance.SetActive(false);
             instances.Push(instance);
         }
     }
 }
 



 using UnityEngine;
 using System.Collections.Generic;
 
 namespace Demo
 {
     public class ObjectPool_B : EnemyFactory
     {
         public int startCount = 21;
 
         List<GameObject> instances = new List<GameObject>();
         List<bool> inUse = new List<bool>();
 
         void Start()
         {
             for (int i = 0; i < startCount; i++)
                 GrowPool();
         }
 
         void GrowPool()
         {
             GameObject instance = Instantiate(prefab);
             instance.SetActive(false);
             instances.Add(instance);
             inUse.Add(false);
         }
 
         public override GameObject Spawn(Transform spawnPoint)
         {
             for (int i = 0; i < inUse.Count; i++)
             {
                 if (inUse[i] == false)
                 {
                     inUse[i] = true;
                     instances[i].transform.SetPositionAndRotation(spawnPoint.position, spawnPoint.rotation);
                     instances[i].SetActive(true);
                     return instances[i];
                 }
             }
             return null;
         }
 
         public override void Despawn(GameObject instance)
         {
             inUse[instances.IndexOf(instance)] = false;
             instance.SetActive(false);
         }
     } 
 }



 using UnityEngine;
 using System.Collections.Generic;
 
 namespace Demo
 {
     public class ObjectPool_C : MonoBehaviour
     {
         // Each prefab gets its own pool.
         static Dictionary<GameObject, ObjectPool_C> m_Pools;
 
         GameObject m_Prefab;
         List<GameObject> m_Instances = new List<GameObject>();
 
         static ObjectPool_C()
         {
             m_Pools = new Dictionary<GameObject, ObjectPool_C>();
         }
 
         public static ObjectPool_C GetPool(GameObject prefab)
         {
             ObjectPool_C pool;
             if (m_Pools.TryGetValue(prefab, out pool))
                 return m_Pools[prefab];
             else
                 return CreateNewPool(prefab);
         }
 
         public static ObjectPool_C CreateNewPool(GameObject prefab, int size = 0)
         {
             GameObject go = new GameObject(prefab.name + " (Pool)");
             ObjectPool_C pool = go.AddComponent<ObjectPool_C>();
             pool.m_Prefab = prefab;
 
             for (int i = 0; i < size; i++)
                 pool.GrowPool();
 
             return pool;
         }
 
         public static GameObject GetInstance(GameObject prefab)
         {
             ObjectPool_C pool = ObjectPool_C.GetPool(prefab);
             return pool.GetInstance();
         }
 
         public GameObject GetInstance()
         {
             GameObject instance = null;
 
             int count = m_Instances.Count;
             for (int i = 0; i < count; i++)
             {
                 if (m_Instances[i].activeSelf == false)
                 {
                     instance = m_Instances[i];
                     instance.SetActive(true);
                     return instance;
                 }
             }
 
             // If we failed to find an inactive instance.
             instance = GrowPool();
             instance.SetActive(true);
             return instance;
         }
 
         GameObject GrowPool()
         {
             GameObject go = Instantiate(m_Prefab, transform);
             go.SetActive(false);
             m_Instances.Add(go);
             return go;
         }
 
         void OnDestroy()
         {
             if (m_Pools != null)
                 m_Pools = null;
         }
     } 
 }
 

The EnemyFactory was just an abstract MonoBehaviour base class, which shows that you can switch the ObjectPool implementation for testing purposes, e.g., via an inspector reference. All implementations have slightly different performance characteristics and may need to be adjusted for specific use-cases.

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image G_H_O_S_T · Mar 07, 2018 at 10:48 AM 0
Share

Thanks for the response. I will check out all that you've sent. I looked up at Brackeys Youtube channel for reference and I have arrived with this code (go easy on me beginner here). I've commented out the part where I tried to make this "growable".

 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 
 public class ObjectPoolerScript : $$anonymous$$onoBehaviour {
 
 [System.Serializable]
     public class Pool {
         public string tag;
         public GameObject prefab;
         public int size;
 //        public bool grow;
     }
 #region Singleton
     public static ObjectPoolerScript Instance;
     private void Awake() {
         Instance = this;
     }
 #endregion
 
     public List<Pool> poolList;
     public Dictionary <string, Queue<GameObject>> poolDictionary;
 
     void Start () {
         poolDictionary = new Dictionary <string, Queue<GameObject>>();
 
         foreach (Pool pool in poolList) {
             Queue<GameObject> objectQueue = new Queue<GameObject>();
 
                 for( int i=0; i< pool.size; i++) {
                     GameObject obj = Instantiate(pool.prefab) as GameObject;
                     obj.transform.parent = GameObject.Find(pool.tag).transform;
                     obj.SetActive(false);
                     objectQueue.Enqueue(obj);
                 }
             poolDictionary.Add(pool.tag, objectQueue);
         }
     }
 
     public GameObject SpawnFromPool (string tag) {
         if (!poolDictionary.Contains$$anonymous$$ey(tag)) {
             Debug.LogWarning("Pool with tag" + tag + "does not exist.");
             return null;
         }
         if (poolDictionary[tag].Count > 0) {
         GameObject objectToSpawn = poolDictionary[tag].Dequeue();
         objectToSpawn.SetActive(true);
         return objectToSpawn;
 //        } else {
 //            foreach(Pool pool in poolList) {
 //                if(pool.grow) {
 //                    pool.size++;
 //                    GameObject objectToSpawn = Instantiate(pool.prefab) as GameObject;
 //                    objectToSpawn.transform.parent = GameObject.Find(pool.tag).transform;
 //                    objectToSpawn.SetActive(true);
 //                    return objectToSpawn;
 //                }
 //            }
         }
         return null;
     }
 
     public void EnqueueObjects (string tag, GameObject gameObject) {
         if (!poolDictionary.Contains$$anonymous$$ey(tag)) {
             Debug.LogWarning("Pool with tag" + tag + "does not exist.");
             return;
         }
 
         poolDictionary[tag].Enqueue(gameObject);
         gameObject.SetActive(false);
         Debug.Log("Enqueued the DEAD");
     }
 }

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

76 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Unity Android lag when close to terrain 0 Answers

Game Freezes upon successive loads 0 Answers

(Unfixable?) iOS frame drops/stutter issues 2 Answers

Problem with Android Framerate Dropping 2 Answers

How to spawn all humans at once and activate then with time? 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges