天天看點

Unity中基于自定義資源配置實作對象池管理1. 對象資訊及執行個體化取得對象2. 定義菜單3. 讀取配置(管理)及執行個體化對象(PoolManager.cs)4. 對象的“銷毀”5. 運作

        此次的實作效果是,将對象池可以批量管理,隻需要提前将對象池的名字、預制體、最大數等配置好,存成資源配置檔案,然後存于本地;運作時讀取配置檔案,将對象池資訊存于字典中,當需要對應的執行個體對象時,隻需給出對象的名字就可從對象池中取得。

        做了一個自定義菜單實作點選菜單時,建立資源配置檔案,以便手動的批量配置對象池。

1. 對象資訊及執行個體化取得對象

1.1 對象資訊及方法(GameObjectPool.cs)

        [Serializable],序列化;可将對象的屬性顯示于Inspector面闆,以便手動配置。

        [SerializeField]序列化字段,可将私有屬性仍顯示于Inspector面闆。

        雖然将批量對象放于字典,但通路時foreach不能一邊通路一邊修改,是以循環周遊字典時用for循環;

        用兩個字典存放對象,一個為正在使用的對象字典,一個為空閑字典,當需要執行個體化時,先從空閑字典中取得;如果所有放于一個字典,當需要對象時則周遊整個字典,兩個字典可以節約性能。

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

/// <summary>
/// 資源池
/// 此資源池将執行個體化出的對象放于根目錄,優化時可将同一類對象放于一個父對象下
/// </summary>
[Serializable]
public class GameObjectPool{
    [SerializeField]//雖為私有成員,但加上[SerializeField]Inspector面闆顯示
    public string name;
    [SerializeField]
    private GameObject prefab;
    [SerializeField]
    private int maxAmount;

    [NonSerialized]
    public List<GameObject> goActiveIsFalseList = new List<GameObject>();//空閑的執行個體(未被使用)
    [NonSerialized]
    public List<GameObject> goActiveIsTrueList = new List<GameObject>();//正在被使用的執行個體

    public GameObject GetIns()
    {

        //當資源被使用完,active為false時就将對象放入未使用的字典中
        //因為GetIns()非每幀執行,二是觸發一次執行一次,是以在觸發最開始先将未使用的執行個體
        //放入goActiveIsFalseList,以便在需要執行個體是保證是最先從goActiveIsFalseList中取得的
        //foreach (GameObject go in goActiveIsTrueList)//foreach不能一邊修改一邊周遊
        for (int i = 0; i < goActiveIsTrueList.Count; i++)
        {
            if (goActiveIsTrueList[i].activeInHierarchy == false)
            {
                GameObject tempgo = goActiveIsTrueList[i];
                goActiveIsTrueList.Remove(goActiveIsTrueList[i]);
                goActiveIsFalseList.Add(tempgo);
            }
        }

        for (int i=0;i< goActiveIsFalseList.Count;i++)
        {//先周遊未使用的資源池,如果池子中有未使用的執行個體
            if(goActiveIsFalseList[i].activeInHierarchy==false)
            {
                goActiveIsFalseList[i].SetActive(true);

                GameObject tempgo = goActiveIsFalseList[i];

                goActiveIsFalseList.Remove(goActiveIsFalseList[i]);
                goActiveIsTrueList.Add(tempgo);//加入到正在使用的字典中

                return tempgo;
            }
        }

        if (goActiveIsTrueList.Count>=maxAmount)//正在使用的池子滿了,就删除第一個
        {
            GameObject.Destroy(goActiveIsTrueList[0]);
            goActiveIsTrueList.RemoveAt(0);
        }
        
        GameObject temp = GameObject.Instantiate(prefab);
        goActiveIsTrueList.Add(temp);
        return temp;
    }
}
           

1.2 對象池字典(GameObjectPoolList.cs)

        繼承自ScriptableObject表示把類GameObjectPoolList變成可以自定義資源配置的檔案。

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


public class GameObjectPoolList:ScriptableObject
{//繼承自ScriptableObject表示把類GameObjectPoolList變成可以自定義資源配置的檔案

    public List<GameObjectPool> poolList;
}

           

2. 定義菜單

        建立一個菜單,當點選時,生成對象池配置檔案。

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

public class PoolManagerEditor : EditorWindow
{
    [MenuItem("PoolTool/Create GameObjectPoolConfig")]
    static void CreateGameObjectPoolList()
    {
        GameObjectPoolList poolList = ScriptableObject.CreateInstance<GameObjectPoolList>();
        //string path = "Assets/Framwork/Resources/gameobjectpool.asset";
        string path = PoolManager.PoolConfigPath;
        AssetDatabase.CreateAsset(poolList, path);
        AssetDatabase.SaveAssets();
    }
}
           

3. 讀取配置(管理)及執行個體化對象(PoolManager.cs)

        GetInstance()方法隻需給出對象名字就可得到對象。

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

/// <summary>
/// 運用單利模式
/// </summary>
public class PoolManager{
    private static PoolManager _instance;

    public static PoolManager Instance
    {
        get
        {
            if(_instance==null)
            {
                _instance = new PoolManager();
            }
            return _instance;
        }
    }

    ///将資源路徑分為三部分,友善後續的更改
    private static string poolConfigPathPrefix = "Assets/Framwork/Resources/";
    private static string poolConfigPathMiddle = "gameobjectpool";
    private static string poolConfigPathPosfix = ".asset";

    public static string PoolConfigPath
    {
        get
        {
            return poolConfigPathPrefix + poolConfigPathMiddle + poolConfigPathPosfix;
        }
    }

    Dictionary<string, GameObjectPool> poolDict;//将配置的資源檔案資訊存入字典,友善使用時根據資源池名字取得執行個體

    private PoolManager()
    {
        GameObjectPoolList poolList = Resources.Load<GameObjectPoolList>(poolConfigPathMiddle);//得到配置的資源檔案

        poolDict = new Dictionary<string, GameObjectPool>();

        foreach(GameObjectPool pool in poolList.poolList)
        {
            poolDict.Add(pool.name, pool);
        }
    }

    /// <summary>
    /// 此方法不做任何事,隻是為了有個調用的方法,調用此方法時就會建立PoolManager的單例對象
    /// </summary>
    public void Init()
    {
        //DoNothing
    }

    /// <summary>
    /// 執行個體化時,根據需要執行個體化的名字從資源池擷取
    /// </summary>
    /// <param name="poolName"></param>
    /// <returns></returns>
    public GameObject GetInstance(string poolName)
    {
        GameObjectPool pool;
        if(poolDict.TryGetValue(poolName,out pool))
        {
            return pool.GetIns();
        }
        //else if
        Debug.LogWarning("Pool: " + poolName + "is not exits!!");
        return null;
    }
}

           

4. 對象的“銷毀”

        為做測試,在預制體上挂一腳本用于将此預制體執行個體化後能隐藏。

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

/// <summary>
/// 相當于做銷毀,挂于Bullet上做測試
/// </summary>
public class DeactiveForTime : MonoBehaviour {

     void OnEnable()
    {
        Invoke("Deactive", 3);//3秒後執行Deactive函數
    }

    void Deactive()
    {
        this.gameObject.SetActive(false);
    }
}
           

5. 運作

        腳本GameScriptsOnScene.cs挂于場景中一物體上,用于觸發。

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

/// <summary>
/// 繼承MonoBehavior,挂于場景中,觸發執行
/// </summary>
public class GameScriptsOnScene : MonoBehaviour {

    private void Awake()
    {
        PoolManager.Instance.Init();//執行個體化出單利對象,Init()為空函數,調用Init隻為執行個體化出PoolManager的單利對象
    }

    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            PoolManager.Instance.GetInstance("Bullet");
        }
        if (Input.GetMouseButtonDown(1))
        {
            PoolManager.Instance.GetInstance("HitEfflect");
        }
    }
}
           
Unity中基于自定義資源配置實作對象池管理1. 對象資訊及執行個體化取得對象2. 定義菜單3. 讀取配置(管理)及執行個體化對象(PoolManager.cs)4. 對象的“銷毀”5. 運作
Unity中基于自定義資源配置實作對象池管理1. 對象資訊及執行個體化取得對象2. 定義菜單3. 讀取配置(管理)及執行個體化對象(PoolManager.cs)4. 對象的“銷毀”5. 運作