欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【Unity】Unity对象池

程序员文章站 2022-07-13 15:01:33
...

Unity 对象池技术
为什么使用对象池?
在我们开发中,往往会遇见需要不断创建和销毁同一物体的情况。(如飞机大战,许多FPS游戏,三消类游戏等),这时我们系统不断的实例化资源和销毁资源对于内存以及性能的消耗是非常大的。对于这种我们可以使用对象池技术进行优化。效果十分明显。
对象池及时的原理:
适用范围:有大量的物体需要被不断的创建和销毁的时候。
关键点:
从对象池中放入对象。
从对象池中取出对象。
使用何种数据类型来对这些对象进行储存。
关键思想:
相比于Instantiate和Destroy,不断的实例化和销毁,对象池只是对它们实例化出的对象进行**和失活的处理。
实现
创建对象通用类:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
//用于通用的对象操作
public class PoolObjectInfo : MonoBehaviour
{
    //资源类型
    public string Type { get { return _Type; } private set { _Type = value; } }
    [SerializeField]
    private string _Type;
    //资源ID 每个创建出来的资源都会有一个唯一的id
    public string AssetID { get { return _AssetID; } private set { _AssetID = value; } }
    [SerializeField]
    private string _AssetID;
    //回收时间
    public float RecoverTime { get { return _RecoverTime; } private set { _RecoverTime = value; } }
    [SerializeField]
    private float _RecoverTime;

    private IEnumerator _iEnumerator;
    //public string Type { get; private set; }
    //public string AssetID { get; private set; }
    //public float RecoverTime { get; private set; }
    void Start()
    {

    }
    //资源开启定时回收
    public void Recover()
    {
        if (RecoverTime == -1 && RecoverTime == 0) 
            return;

        if (_iEnumerator!=null)
        {
            StopCoroutine(_iEnumerator);
        }
        _iEnumerator = RecoverGameObj();
        StartCoroutine(_iEnumerator);
    }
    IEnumerator RecoverGameObj()
    {
        yield return new WaitForSeconds(RecoverTime);
        PoolManager.Instance.RecoverGameObj(gameObject);
        _iEnumerator = null;
    }
    private void OnDisable()
    {
        if (_iEnumerator != null)
        {
            StopCoroutine(_iEnumerator);
        }
    }
    public void InitData(string type,float time=-1)
    {
        if (Type==null)
        {
            Type = type;
            AssetID = Guid.NewGuid().ToString("N");
            RecoverTime = time;
        }
    }
    public void ResetInfo()
    {
        if (Type != null)
        {
            AssetID = Guid.NewGuid().ToString("N");
        }
    }

}

创建用于unity拖拽的属性

[Serializable]
public class PoolObject {
    public string Name;//名字
    public float RecoverTime=-1;//回收时间
    public GameObject GameObj;//对象
}

创建管理类

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public class PoolManager : MonoBehaviour {

    private Dictionary<string, Dictionary<string, GameObject>> _dtGameObjUsingPool = new Dictionary<string, Dictionary<string, GameObject>>();
    private Dictionary<string, Dictionary<string, GameObject>> _dtGameObjFreePool = new Dictionary<string, Dictionary<string, GameObject>>();
    private Dictionary<string, PoolObject> _dtGameObj = new Dictionary<string, PoolObject>();

    public List<PoolObject> _LstGameObj;
    public static PoolManager Instance { get; private set; }
    // Use this for initialization
    void Start() {//初始化
        Instance = this;
        for (int i=0;i<_LstGameObj.Count;i++) {
            if (_dtGameObj.ContainsKey(_LstGameObj[i].Name))
            {
                Debug.LogWarning(_LstGameObj[i].Name+ "  Repeat addition  !");

            }
            else
            {
                _dtGameObj.Add(_LstGameObj[i].Name, _LstGameObj[i]);
            }

        }

        foreach (string item in _dtGameObj.Keys)
        {
            Debug.Log(item);
        }
    }

    // Update is called once per frame
    void Update() {

    }
    private void Pool()
    {

    }
    //得到一个对象
    public GameObject GetGameObj(string name, Transform parent = null) {
        KeyValuePair<string, GameObject> keyValuePair=new KeyValuePair<string, GameObject>();
        if (_dtGameObjFreePool.ContainsKey(name)&& _dtGameObjFreePool[name].Count!=0)
        {
            Dictionary<string, GameObject>.Enumerator freePoolE = _dtGameObjFreePool[name].GetEnumerator();
            freePoolE.MoveNext();
            keyValuePair = freePoolE.Current;
            _dtGameObjFreePool[name].Remove(keyValuePair.Key);
        }
        else
        {
            if (_dtGameObj.ContainsKey(name)) {
                GameObject gameObj = Instantiate(_dtGameObj[name].GameObj) as GameObject;
                gameObj.AddComponent<PoolObjectInfo>();
                gameObj.GetComponent<PoolObjectInfo>().InitData(name, _dtGameObj[name].RecoverTime);
                keyValuePair=new KeyValuePair< string,GameObject> (gameObj.GetComponent<PoolObjectInfo>().AssetID,gameObj);
            }
            else
            {
                Debug.LogWarning( name + " not found ");
                return null;
            }

        }
        if (keyValuePair.Key==null)
        {
            Debug.LogWarning(name + " not found ");
            return null;
        }
        if (!_dtGameObjUsingPool.ContainsKey(name))
        {
            _dtGameObjUsingPool.Add(name,new Dictionary<string, GameObject>());
        }
        if (parent != null)
        {
            keyValuePair.Value.transform.SetParent(parent);
        }
        _dtGameObjUsingPool[name].Add(keyValuePair.Key,keyValuePair.Value);
        return keyValuePair.Value;
    }

    public GameObject GetGameObj(string name,string assetId, Transform parent = null)
    {
        if (_dtGameObjFreePool.ContainsKey(name) && _dtGameObjFreePool[name].ContainsKey(assetId))
        {

            if (!_dtGameObjUsingPool.ContainsKey(name))
            {
                _dtGameObjUsingPool.Add(name, new Dictionary<string, GameObject>());
            }
            GameObject res = _dtGameObjFreePool[name][assetId];
            _dtGameObjUsingPool[name].Add(assetId, res);
            _dtGameObjFreePool[name].Remove(assetId);
            if (parent != null)
            {
                res.transform.SetParent(parent);
            }
            return res;
        }
        else
        {
            Debug.LogWarning(name + " not found ");


        }
        return null;
    }

    public T GetGameObj<T>(string name,Transform parent=null)
    {
        KeyValuePair<string, GameObject> keyValuePair = new KeyValuePair<string, GameObject>();
        if (_dtGameObjFreePool.ContainsKey(name) && _dtGameObjFreePool[name].Count != 0)
        {
            Dictionary<string, GameObject>.Enumerator freePoolE = _dtGameObjFreePool[name].GetEnumerator();
            freePoolE.MoveNext();
            keyValuePair = freePoolE.Current;
            _dtGameObjFreePool[name].Remove(keyValuePair.Key);
        }
        else
        {
            if (_dtGameObj.ContainsKey(name))
            {
                GameObject gameObj = Instantiate(_dtGameObj[name].GameObj) as GameObject;
                gameObj.AddComponent<PoolObjectInfo>().InitData(name, _dtGameObj[name].RecoverTime);
                keyValuePair = new KeyValuePair<string, GameObject>(gameObj.GetComponent<PoolObjectInfo>().AssetID, gameObj);
            }
            else
            {
                Debug.LogWarning(name + " not found ");
                return default(T);
            }

        }
        if (keyValuePair.Key == null || keyValuePair.Value.GetComponent<T>()==null)
        {
            Debug.LogWarning(name + " not found ");
            return default(T);
        }
        if (!_dtGameObjUsingPool.ContainsKey(name))
        {
            _dtGameObjUsingPool.Add(name, new Dictionary<string, GameObject>());
        }
        _dtGameObjUsingPool[name].Add(keyValuePair.Key, keyValuePair.Value);
        if (parent != null)
        {
            keyValuePair.Value.transform.SetParent(parent);
        }
        return keyValuePair.Value.GetComponent<T>();
    }

    public T GetGameObj<T>(string name, string assetId, Transform parent = null)
    {
        if (_dtGameObjFreePool.ContainsKey(name) && _dtGameObjFreePool[name].ContainsKey(assetId))
        {

            if (!_dtGameObjUsingPool.ContainsKey(name))
            {
                _dtGameObjUsingPool.Add(name, new Dictionary<string, GameObject>());
            }
            GameObject res = _dtGameObjFreePool[name][assetId];
            _dtGameObjUsingPool[name].Add(assetId, res);
            _dtGameObjFreePool[name].Remove(assetId);
            if (res.GetComponent<T>()==null)
            {
                Debug.LogWarning(name + " not found ");
                return default(T); 
            }
            if (parent != null)
            {
                res.transform.SetParent(parent);
            }
            return res.GetComponent<T>();
        }
        else
        {
            Debug.LogWarning(name + " not found ");
        }
        return default(T); 
    }
    public void RecoverGameObj(GameObject gameObj)
    {
        PoolObjectInfo info = gameObj.GetComponent<PoolObjectInfo>();
        gameObj.SetActive(false);
        if (info == null)
        {
            return;
        }
        if (!_dtGameObjFreePool.ContainsKey(info.Type))
        {
            _dtGameObjFreePool.Add(info.Type, new Dictionary<string, GameObject>());
        }
        if (_dtGameObjUsingPool[info.Type].ContainsKey(info.AssetID))
        {
            _dtGameObjUsingPool[info.Type].Remove(info.AssetID);
            _dtGameObjFreePool[info.Type].Add(info.AssetID, gameObj);
        }

    }
    public void RecoverGameObj(string name)
    {
        if (!_dtGameObjUsingPool.ContainsKey(name))
        {
            return;
        }
        foreach(GameObject o in _dtGameObjUsingPool[name].Values)
        {
            RecoverGameObj(o);
        }
    }
}

写完了PoolManager拖到场景中一个固定对象中
【Unity】Unity对象池
然后就可以通过名字正常调用了
PoolManager.Instance.GetGameObj(“LinePrefabs”,transform);
【Unity】Unity对象池