当前位置:网站首页>Unity3d: special effect object pool, timeout delete GameObject in the pool, GC weight

Unity3d: special effect object pool, timeout delete GameObject in the pool, GC weight

2022-07-23 12:45:00 Sixi Liyu

Technical points :

  1. Unused particles return to the buffer pool
  2. Create a pool according to the name of a single particle , When a The last operation time on the pool ( Recovery object ) Threshold exceeded , Delete one in the pool every once in a while GameObject, It can be configured for a single particle , Frequently used , Longer dwell time
  3. A complete pool is deleted , increase GC A weight ,GC When the weight reaches the maximum value, call System.GC.Collect()

Have a problem :

  1. Parent node OnDisable, You cannot set the parent object of a child node
    Cannot set the parent of the GameObject ''XXX“ while activating or deactivating the parent GameObject “XXX” , Because when the parent object enters the recycling pool , The code is modifying the parent node of the child node of this object . The modification method is : Set a layer of empty objects for child nodes
  2. After recycling, transfer it out of the pool , Particles show only half , Or don't show
    Every time the particles are taken out , If the last particle is in scroll Use in , Cutting shader Under the influence of , There will be half cutting , To reset the particle clipping area
        public void ResetMaskParams(Material mat)
        {
    
            mat.SetFloat("_MinX", -1);
            mat.SetFloat("_MinY", -1);
            mat.SetFloat("_MaxX", 1);
            mat.SetFloat("_MaxY", 1);
        }
  1. Some particles have special treatment , For example, destroy sub objects when used up ; Or mounting scripts will lose references , Do not put it into the buffer pool

Code

Get particles

A simple test , Really use resid Instead of objPrefab, And use Assetbundle Synchronous loading

public GameObject GetEffect(GameObject objPrefab)
        {
    
            string name = GetNoCloneName(objPrefab.name);
            GameObject obj = null;
            if (m_dicPool.ContainsKey(name))
            {
    
                if (m_dicPool[name] != null && m_dicPool[name].Count > 0)
                {
    
                    obj = m_dicPool[name].Dequeue();
                    while (obj == null && m_dicPool[name].Count > 0)
                    {
    
                        obj = m_dicPool[name].Dequeue();
                        if (obj != null)
                        {
    
                            //return obj;
                            break;
                        }
                    }
                    if (obj == null)
                    {
    
                        obj = GameObject.Instantiate(objPrefab) as GameObject;
                    }

                }
                else
                {
    
                    obj = GameObject.Instantiate(objPrefab) as GameObject;
                }
            }
            else
            {
    
                m_dicPool[name] = new Queue<GameObject>(m_count);
                obj = GameObject.Instantiate(objPrefab) as GameObject;
            }
            obj.SetActive(true);
            SetInDicUse(obj);
            return obj;
        }

Recycling particles

public void RecycleEffect(GameObject obj)
        {
    

            if (obj == null)
            {
    
                return;
            }
            
            // Add the name of the particles to be filtered and not recycled , Or conditions 
            string name = GetNoCloneName(obj.name);


            m_lastUsedTime[name] = Time.time;
            SetOutDicUse(obj);
            obj.transform.SetParent(GetEffectPoolObj());
            obj.SetActive(false);

            if (m_dicPool.ContainsKey(name))
            {
    
                if (m_dicPool[name] == null)
                {
    
                    m_dicPool[name] = new Queue<GameObject>(m_count);
                }
                m_dicPool[name].Enqueue(obj);
            }
            else
            {
    
                m_dicPool[name] = new Queue<GameObject>(m_count);
                m_dicPool[name].Enqueue(obj);
            }
        }

The particle pool timed out and is no longer used ,Destroy One GameObject

private void FixedUpdate()
{
    
foreach (var item in m_lastUsedTime)
                {
    
                    string keyName = item.Key;
                    float lastTime = item.Value;
                    if (m_dicUse.ContainsKey(keyName) && m_dicUse[keyName].Count == 0)
                    {
    
                        if (m_dicPool.ContainsKey(keyName))
                        {
    
                            if (m_dicPool[keyName].Count > 0)// There are still free objects in a pool 
                            {
    
                                if (Time.time - lastTime > GetDeleOneObjTimeClip(m_dicPool[keyName].Count)) //  Timeout to remove an idle object 
                                {
    
                                    GameObject idleObj = m_dicPool[keyName].Dequeue();
                                    GameObject.Destroy(idleObj);
                                    timeUpdateList.Add(keyName);
                                }
                            }
                            else// There are no free objects in a pool 
                            {
    
                                if (Time.time - lastTime > mResReleaseTime)
                                {
    
                                    releaseList.Add(keyName);
                                }

                            }
                        }
                    }
                }


                for (int i = 0; i < timeUpdateList.Count; i++)
                {
    
                    m_lastUsedTime[timeUpdateList[i]] = Time.time; //  Last time a certain... In the buffer pool was deleted obj Time for 
                }

GC A weight

public void AddUnloadWeights(int nWeights = 1)
        {
    
            m_nSumWeights += nWeights;
        }

        void Update()
        {
    
            // Every time 60 Frame performs a detection 
            if (Time.frameCount % CHECK_INTERVAL_FRAME == 0)
            {
    
                TryUnloadUnusedAssets();
            }
        }

        void TryUnloadUnusedAssets()
        {
    
            if ((Time.realtimeSinceStartup - m_fLastUnloadTime >= m_nMaxInterval)
                || (m_nSumWeights >= m_nWeightsThreshold))
            {
    
                DoUnloadUnusedAssets();
            }
        }

        void DoUnloadUnusedAssets()
        {
    
            Resources.UnloadUnusedAssets();
            System.GC.Collect();
            m_nSumWeights = 0;
            m_fLastUnloadTime = Time.realtimeSinceStartup;

        }

Source code

https://github.com/luoyikun/UnityForTest
EffectPoolMgr.cs

原网站

版权声明
本文为[Sixi Liyu]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/204/202207230540018539.html