1. 程式人生 > >Unity 物件池的簡單介紹(Dictionary使用)

Unity 物件池的簡單介紹(Dictionary使用)

使用物件池的目的:增加頻繁使用的遊戲物體的   複用性  (遊戲物體(敵人小兵)反覆的建立與銷燬  會消耗比較多的效能)

建立物件池的步驟:

1.建立一個存放物件的字典(物件池)

2.對物件池的操作方法

2.1建立物件                     CreateObject()

2.2為物件池新增元素       Add()

2.3尋找可以使用的物件   FindUseObj()

2.4回收物件                     CollectObject()

3.釋放資源                       Clear();

實現如下

1.實現一個單例,用於管理程式碼

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


public class MonoSingleton<T>:MonoBehaviour where T:Component
{

    private static T t;
    public static T Intance{
        get{
            t = GameObject.FindObjectOfType(typeof(T)) as T;
            if(t==null)
            {
                GameObject go = new GameObject();
                t = go.AddComponent<T>();
                go.name = t + "Object";
            }
            //在場景切換時不要銷燬
            DontDestroyOnLoad(t);
            return t;
        }
    }
}
2.實現物件池
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 物件(頻發使用的遊戲物體)  子彈  技能 敵人
/// </summary>
public class ObjectPool : MonoSingleton<ObjectPool> {



    //1.欄位  池   例如:橫掃千軍   技能預製件(因為一個技能可能有多個預製件) 技能的複用性
    private Dictionary<string, List<GameObject>> cache =
        new Dictionary<string, List<GameObject>>();
    int i = 0;
    //2.方法
    //2.1 建立
    //工具類   載入資源   字典  名稱  資源
    /// <summary>
    /// 建立顯示物件
    /// </summary>
    /// <returns>The object.</returns>
    /// <param name="key">物件名稱</param>
    /// <param name="go">物件的預製件</param>
    /// <param name="position">物件的新位置</param>
    /// <param name="quaternion">物件的角度</param>
    public GameObject CreateObject(string key,GameObject go,Vector3 position,Quaternion quaternion)
    {
        //從池中取出可以使用的物件
        GameObject tempgo = FindUseObj(key);
        if(tempgo!=null)
        {
            tempgo.transform.position = position;
            tempgo.transform.rotation = quaternion;
        }
        else{
            tempgo = Instantiate(go, position, quaternion) as GameObject;
            print(i++);
            Add(key,tempgo);
        }
        tempgo.SetActive(true);

        return tempgo;
    }
	/// <summary>
    /// 為物件池新增元素
    /// </summary>
    /// <returns>The add.</returns>
    /// <param name="key">Key.</param>
    /// <param name="tempGo">Temp go.</param>
    public void Add(string key, GameObject tempGo)
    {
        //物件池當中如果沒有鍵(新增鍵)
        if(!cache.ContainsKey(key))
        {
            cache.Add(key,new List<GameObject>());
        }
        //找到相應的值,為這個列表中新增tempGo
        //List中的Add方法
        //物件池中有鍵就直接在其list中新增值
        cache[key].Add(tempGo);
    }
    /// <summary>
    /// 尋找可以使用的物件
    /// </summary>
    /// <returns>The use object.</returns>
    /// <param name="key">鍵</param>
    public GameObject FindUseObj(string key)
    {
        //在池中且未被使用的物件
        if(cache.ContainsKey(key))
        {
            //返回找到的第一個可用的物件(沒有返回 null)
            return cache[key].Find(p=>!p.activeSelf);
            /*上面(泛型委託Lambda)這句話的意思
             *p=cache[key][i]
             *if(!cache[key][i].activeSelf=!p.activeSelf)
             *
             *實現的方法如下
             * for(int i;i<cache[key].Count;i++)
             * {
             * if(!cache[key][i].activeSelf)
             *     return cache[key][i];
             * }
            */
        }
        return null;
    }
    /// <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(cache.ContainsKey(key))
        {
            //Destroy當中所有的物件
            for (int i = 0; i < cache[key].Count;i++)
            {
                Destroy(cache[key][i]);
            }
            //清除鍵當中的所有值
            //cache[key].Clear();
            //清除這個鍵(鍵值一起清除)
            cache.Remove(key);
        }
    }
    /// <summary>
    /// 釋放所有物件池
    /// </summary>
    public void ClearAll()
    {
        var list = new List<string>(cache.Keys);
        for (int i = 0; i < list.Count;i++)
        {
            Clear(list[i]);
        }
    }

}

3.簡單使用物件池
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PoolTest : MonoBehaviour {

    GameObject go;
    GameObject item;
	// Use this for initialization
	void Start () {
        //在Resources檔案下載入Cube預製鍵
        go = Resources.Load("Cube") as GameObject;
	}
	
	// Update is called once per frame
	void Update () {
        //按下空格建立一個Cube
        if(Input.GetKeyDown(KeyCode.Space))
        {
            item = ObjectPool.Intance.CreateObject("Object1", go, Vector3.zero, new Quaternion(0, 0, 0, 0));

        }
        //按下左鍵執行回收
        if(Input.GetMouseButtonDown(0))
        {
            if (item != null)
            {
                ObjectPool.Intance.CollectObject(item, 2);
            }
        }
        //按下右鍵執行清除
        if(Input.GetMouseButtonDown(1))
        {
            ObjectPool.Intance.Clear("Object1");
        }
	}
}