unity对象池的使用

这两天在制作主角的技能以及攻击方式,其中就涉及到关于大量创造与回收物体,比如主角发射一个小火球。假如使用最基础的方式,当然就是不断地通过new对象来进行实例化,然后再用碰撞检测来destroy掉这个火球,这是最开始学习的时候使用的方式。
但是这种方式就会面临一个非常大的问题,就是对性能会产生一个巨大的消耗,当我们频繁的去new对象的时候,每次都会在内存的托管堆上去分配一个空间,然后destroy的时候,只是会将资源释放,内存空间并没有被GC回收,这样就会造成内存的巨大浪费。
怎么解决呢?这时候就出现了对象池这个东西。对象池其实简单通俗的来说,就是对对象的一个管理,当我们需要这个物体的时候,比如说子弹,就实例化这个子弹出来,然后当子弹打中人或者消失,就将子弹的active设置为false,然后下一次发射子弹的时候呢,就不需要去实例化这个子弹,而是将刚才的子弹设置为true(当然,假如需要在短时间内发射很多颗子弹的话,还是需要实例化多颗子弹,但是对象池的使用可以让这种实例化的情况尽量减少)
接下来看看对象池的编写:

首先是编写一个单例模式的基类:

public class MonoSingleton<T> : MonoBehaviour where T: Component
{
    public static T m_instance=null;
    public static T Intance
    {
        get
        {
            m_instance = GameObject.FindObjectOfType(typeof(T)) as T;

            if (m_instance == null)
            {
                GameObject go = new GameObject();
                m_instance = go.AddComponent<T>();
                go.name = m_instance + "Objectaaaaa";
            }
            //在场景切换时不要销毁
            DontDestroyOnLoad(m_instance);
            return m_instance;
        }
    }
   
}

然后是对象池
借鉴了这个博客https://blog.csdn.net/leonardo_davinci/article/details/78646562

public class ObjectsPool : MonoSingleton<ObjectsPool>
{
    public Dictionary<string, List<GameObject>> dictionary = new Dictionary<string, List<GameObject>>();
    //public GameObject m_obj;
    /// <summary>
    /// 得到存储在对象池中间的预制体
    /// </summary>
    /// <param name="_name">传入键的名字</param>
    /// <returns></returns>
    public GameObject GetInstanse(string _name)
    {
        Debug.Log(_name);
        string str ="Prefabs/" + _name;
        if (dictionary.ContainsKey(_name))
        {
            for(int i = 0; i < dictionary[_name].Count; i++)
            {
                //取值
                if (!dictionary[_name][i].activeSelf)
                {
                    dictionary[_name][i].SetActive(true);
                    return dictionary[_name][i];
                }
            }
            //list数组中当第一个被存储的物体被取出的时候,此时需要第二个相同的物体,就直接实例化一个出来。存储在list数组的第二个空间中
            //这样就可以最大限度的减少需要实例化的物体
            GameObject object1 = Instantiate(Resources.Load("Prefabs/"+_name)) as GameObject;
            dictionary[_name].Add(object1);
            return object1;
        }
        //假如不存在这个键值对,就添加这个键值对
        GameObject object2 = Instantiate(Resources.Load("Prefabs/"+_name)) as GameObject;
        AddObject(_name, object2);
        return object2;
        
    }
    public void TestFun()
    {
        Debug.Log("testfun");
    }
    public void AddObject(string name,GameObject obj)
    {
        List<GameObject> list = new List<GameObject>();
        list.Add(obj);
        dictionary.Add(name, list);
        obj.SetActive(false);
    }
    /// <summary>
    /// 直接回收
    /// </summary>
    /// <param name="go">Go.</param>
    public void CollectObject(GameObject go)
    {
        go.SetActive(false);
    }
    /// <summary>
    /// 延迟回收
    /// </summary>
    /// <param name="go">Go.</param>
    /// <param name="delay">Delay.</param>
    public void CollectObject(GameObject go, float delay)
    {
        StartCoroutine(Collect(go, delay));
    }
    private IEnumerator Collect(GameObject go, float delay)
    {
        yield return new WaitForSeconds(delay);
        CollectObject(go);
    }
    /// <summary>
    /// 释放资源
    /// </summary>
    /// <returns>The clear.</returns>
    /// <param name="key">Key.</param>
    public void Clear(string key)
    {
        if (dictionary.ContainsKey(key))
        {
            //Destroy当中所有的对象
            for (int i = 0; i < dictionary[key].Count; i++)
            {
                Destroy(dictionary[key][i]);
            }
            //清除键当中的所有值
            //dictionary[key].Clear();
            //清除这个键(键值一起清除)
            dictionary.Remove(key);
        }
    }
    /// <summary>
    /// 释放所有对象池
    /// </summary>
    public void ClearAll()
    {
        List<string> list = new List<string>(dictionary.Keys);
        for (int i = 0; i < list.Count; i++)
        {
            Clear(list[i]);
        }
    }

}

然后绑在生产者上的生产脚本

{
   public Transform tra;
   private GameObject fireball;
   private GameObject gameObj;
   private string _name;
    public Vector3 managerposition;
    public Vector3 maposition;
    public Vector3 nor;
    public float stay_time;
    public FireBallController ballController;
    // Start is called before the first frame update
    void Awake()
    {
         
        _name = "FireBalls";
        gameObj =Instantiate(Resources.Load("Prefabs/"+_name)) as GameObject;
        gameObj.SetActive(false);
        
    }

    // Update is called once per frame
    void Update()
    {
        managerposition = GameObject.Find("Manager").transform.position;
        maposition = GameObject.Find("Ma").transform.position;
        nor = (managerposition - maposition).normalized;
        
        if (Input.GetKeyDown(KeyCode.J))
        {
        

            fireball = ObjectsPool.Intance.GetInstanse(_name);
            fireball.transform.position = tra.position;
        }
  

然后再在火球上绑定火球的运行脚本就OK了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值