unity中實現簡單對象池,附教程原理


Unity對象池的創建與使用


本文提供全流程,中文翻譯。

Chinar 堅持將簡單的生活方式,帶給世人!

(擁有更好的閱讀體驗 —— 高分辨率用戶請根據需求調整網頁縮放比例)



Chinar —— 心分享、心創新!

助力快速完成 Unity 對象池的創建與使用

為新手節省寶貴的時間,避免采坑!


Chinar 教程效果:



全文高清圖片,點擊即可放大觀看 (很多人竟然不知道)


1

MonoSingleton —— 單例基類


任何繼承自 MonoSingleton 泛型基類的腳本/類 都是單例類

舉個栗子黑白88

using UnityEngine;


/// <summary>
/// 泛型單例基類 —— 任何繼承自該類的類,都是單例類
/// </summary>
/// <typeparam name="T">泛型</typeparam>
public abstract class MonoSingleton<T> : MonoBehaviour where T : MonoSingleton<T>
{
    private static T instance;
    public static T Instance
    {
        get
        {
            if (instance == null)
            {
                instance = FindObjectOfType(typeof(T)) as T;
                if (instance == null) instance = new GameObject("Chinar Single of " + typeof(T).ToString(), typeof(T)).GetComponent<T>();
            }

            return instance;
        }
    }


    private void Awake()
    {
        if (instance == null) instance = this as T;
    }


    private void OnApplicationQuit()
    {
        instance = null;
    }
}

2

ObjectPool —— 對象池


新建一個腳本 ObjectPool 繼承自泛型基類 MonoSingleton《ObjectPool》

是以 ObjectPool 就會是一個單例類
舉個栗子黑白88

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


/// <summary>
/// 對象池(重復調用/使用的游戲物體) 子彈,技能,導彈,敵人
/// </summary>
public class ObjectPool : MonoSingleton<ObjectPool>
{
    //字段 池 技能預設物(因為一個技能可能有多個預制件) 技能的復用性
    private Dictionary<string, List<GameObject>> cache = new Dictionary<string, List<GameObject>>();
    int                                          i     = 0; //標記 0


    /// <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 = cache.ContainsKey(key) ? cache[key].Find(p => !p.activeSelf) : null; //返回池中未激活的對象,所有都被激活就返回空,賦值給臨時對象
        if (tempgo != null)                                                                      //如果臨時對象不為空
        {
            tempgo.transform.position = position;   //設置位置
            tempgo.transform.rotation = quaternion; //旋轉信息
        }
        else //否則,就是空了。(也就是沒能從池子里取出對象)
        {
            tempgo = Instantiate(go, position, quaternion); //那就根據傳入的預設物,生成一個新物體
            print("實例化物體數量:" + i++);
            if (!cache.ContainsKey(key)) //池中沒有鍵
            {
                cache.Add(key, new List<GameObject>()); //新建一個 列表
            }

            cache[key].Add(tempgo); //給字典中的列表加入/add 臨時物體,如果有鍵就直接添加了
        }

        tempgo.SetActive(true); //並啟用臨時物體
        return tempgo;          //返回
    }


    /// <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

PoolTest —— 測試對象池的使用


新建一個腳本 PoolTest 用來測試對象池的使用
舉個栗子黑白88

using UnityEngine;


/// <summary>
/// 測試對象池的調用
/// </summary>
public class PoolTest : MonoBehaviour
{
    GameObject go;   //臨時對象
    GameObject item; //臨時對象池對象


    void Start()
    {
        go = Resources.Load<GameObject>("Cube"); //在Resources文件目錄下做一個Cube預設物
    }


    void Update()
    {
        if (Input.GetKey(KeyCode.Space)) //按下空格創建一個Cube
        {
            item                    =  ObjectPool.Instance.CreateObject("Object1", go, Vector3.zero, new Quaternion(0, 0, 0, 0));
            item.transform.position += new Vector3(0, 0, 1);
        }


        if (Input.GetMouseButtonDown(0)) //按下左鍵執行回收對象
        {
            if (item != null)
            {
                ObjectPool.Instance.CollectObject(item, 0.2f);
            }
        }


        if (Input.GetMouseButtonDown(1)) //按下右鍵執行清除已經生成的對象
        {
            ObjectPool.Instance.Clear("Object1");
        }
    }
}

支持

May Be —— 搞開發,總有一天要做的事!


擁有自己的服務器,無需再找攻略!

Chinar 提供一站式教程,閉眼式創建!

為新手節省寶貴時間,避免采坑!


先點擊領取 —— 阿里全產品優惠券 (享受最低優惠)


1 —— 雲服務器超全購買流程 (新手必備!)

2 —— 阿里ECS雲服務器自定義配置 - 購買教程(新手必備!)

3—— Windows 服務器配置、運行、建站一條龍 !

4 —— Linux 服務器配置、運行、建站一條龍 !





Chinar


END

本博客為非營利性個人原創,除部分有明確署名的作品外,所刊登的所有作品的著作權均為本人所擁有,本人保留所有法定權利。違者必究

對於需要復制、轉載、鏈接和傳播博客文章或內容的,請及時和本博主進行聯系,留言,Email: ichinar@icloud.com

對於經本博主明確授權和許可使用文章及內容的,使用時請注明文章或內容出處並注明網址


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM