对象池的使用

为了避免重复创建开销比较大的对象,我们可以通过对象池来优化。
对象池的思路比较简单,事先创建好一批对象,放到一个集合中,以后每当程序需要新的对象时候,都从对象池里获取,每当程序用完该对象后,都把该对象归还给对象池。这样会避免重复的对象创建,提高程序性能。
注:如果是动态创建对象池,开始时对象池的List或数组是空的,可以先创建一个然后加入到对象池中,这样就可以开始使用了。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;


namespace ns
{
    
    

    public interface IResetable
    {
    
    
        void OnReset();
    }

    ///<summary>
    ///
    ///</summary>
    public class GameObjectPool : MonoSingleton<GameObjectPool>
    {
    
    
        private Dictionary<string, List<GameObject>> cache;

        private void Awake()
        {
    
    
            cache = new Dictionary<string, List<GameObject>>();
        }

        //public GameObject CreateObject(string key, GameObject prefab, Vector3 pos, Quaternion dir)
        //{
    
    
        //    //在池中查找禁用的物体
        //    GameObject go = null;
        //    if (cache.ContainsKey(key))
        //        go = cache[key].Find(o => !o.activeInHierarchy);
        //    if (go != null)
        //    {
    
    
        //        go.transform.position = pos;
        //        go.transform.rotation = dir;
        //        go.SetActive(true);
        //    }
        //    else
        //    {
    
    
        //        go = Instantiate(prefab, pos, dir);
        //        if (!cache.ContainsKey(key)) cache.Add(key, new List<GameObject>());
        //        cache[key].Add(go);
        //    }
        //    return go;
        //}

        /// <summary>
        /// 使用对象池创建对象
        /// </summary>
        /// <param name="key">对象种类</param>
        /// <param name="prefab">对象预制件</param>
        /// <param name="pos">位置</param>
        /// <param name="dir">旋转</param>
        /// <returns></returns>
        public GameObject CreateObject(string key, GameObject prefab, Vector3 pos, Quaternion dir)
        {
    
    
            //1. 在池中查找可以使用的对象
            GameObject go = FindUsableObject(key);
            //2. 如果没有找到,则创建再加入池中。
            if (go == null)
            {
    
    
                go = Instantiate(prefab);
                Add(key, go);
            }
            //3.使用对象
            UseObject(pos, dir, go);
            return go;
        }

        private void UseObject(Vector3 pos, Quaternion dir, GameObject go)
        {
    
    
            go.transform.position = pos;
            go.transform.rotation = dir;
            go.SetActive(true);
 
            //go.GetComponent<Bullet>().CalculateTargetPosition();
            //go.GetComponent<IResetable>().OnReset();
            //遍历物体中所有需要重置的脚本
            foreach (var item in go.GetComponents<IResetable>())
            {
    
    
                item.OnReset();
            }
        }

        private void Add(string key, GameObject go)
        {
    
    
            if (!cache.ContainsKey(key)) cache.Add(key, new List<GameObject>());
            cache[key].Add(go);
        }

        private GameObject FindUsableObject(string key)
        {
    
    
            //字典如果存在当前记录,则在集合中查找禁用的物体
            if (cache.ContainsKey(key))
                return cache[key].Find(o => !o.activeInHierarchy);
            return null;
        }

        /// <summary>
        /// 立即回收
        /// </summary>
        /// <param name="go"></param>
        public void CollectObject(GameObject go)
        {
    
    
            go.SetActive(false);
        }

        /// <summary>
        /// 延迟回收
        /// </summary>
        /// <param name="go"></param>
        public void CollectObject(GameObject go,float delay)
        {
    
    
            StartCoroutine(DelayCollect(go, delay));
        }

        private IEnumerator DelayCollect(GameObject go, float delay)
        {
    
    
            yield return new WaitForSeconds(delay);
            CollectObject(go);
        }

        public void Clear(string key)
        {
    
    
            //释放游戏对象
            foreach (var item in cache[key])
            {
    
    
                Destroy(item);
            }
            //移除键
            cache.Remove(key);
        }
         
        public void ClearAll()
        {
    
    
            //Bug 1:异常 -- 无效的操作
            List<string> keyList = new List<string>(cache.Keys);
            foreach (var item in keyList)
            {
    
    
                //遍历集合  移除字典记录
                Clear(item);
            } 
        }

        //Bug 2 : 子弹不能沿枪的正前方发射 
        //解决方案:每次通过对象池创建对象,都调用IResetable接口方法,达到逻辑(计算目标点)重置的目的。
    }
}

猜你喜欢

转载自blog.csdn.net/qq_22975451/article/details/114137059