對Unity有一點瞭解的人一定知道,執行個體化對象是非常消耗效能的,而摧毀對象消耗少一點但同樣會影響效能,所以為了最佳化,把常用的對象存入對象池,在調用時從中取出,在不使用的時候隱藏放入對象池,這樣就可以大大節省資源的消耗。
一.使用定製資源設定檔
http://www.360doc.com/content/14/0323/13/12282510_363016017.shtml
在寫對象池前需要知道的一些東西,這種定製資源配置技術可以讓我們寫的對象池更方便的使用,它可以讓我們直接在一個儲存的自訂設定檔中來進行對對象池的操作,啟動並執行時候會自動幫我們載入,非常方便,當然我們也可以直接把寫好的對象池指令碼掛在一個對象把它做成Prefab來使用但很明顯這樣非常的不舒服且不方便。
並不需要非常清楚的瞭解這個技術,大概知道怎麼使用就可以開始了。
二.建立GameObjectPool類
首先我們建立一個Pool類,它應該有名字,預物體,最大容量以及用以儲存執行個體化對象的List集合,還要對外提供一個取對象的方法。
[Serializable]public class GameObjectPool { public string name; [SerializeField] private GameObject prefab; [SerializeField] private int maxCount; [NonSerialized] private List<GameObject> goList;
public GameObject GetInst() { foreach (GameObject item in goList) //遍曆是否存在閒置對象,如果有返回 { if (!item.activeInHierarchy) return item; } if(goList.Count>=maxCount) //發現不存在空閑對象,在建立新對象前要先判斷是否達到容量,如果達到,銷毀最早的對象 { GameObject.Destroy(goList[0]); goList.RemoveAt(0); } GameObject temp = GameObject.Instantiate(prefab) as GameObject; //建立新對象加入集合并返回 goList.Add(temp); return temp; }}
注意一定要在類前加上Serializable特性使Pool類可以被序列化,如果不想把有些欄位寫成public,可以在用SerializeField來修飾就可以在編輯器中操作了,對於不需要序列化的欄位比如goList儲存著遊戲中產生的對象,不需要在設定檔中進行操作就可以加上NonSerialized特性即可
三.建立PoolList類
建立PoolList類,儲存了對象池集合,關鍵在於它要繼承ScriptableObject類
public class PoolList :ScriptableObject { public List<GameObjectPool> poolList;} 四.擴充Unity編輯器
[MenuItem("Manager/Create PoolListConfigure")] static void CreatePoolListConfigure() { PoolList poolList=ScriptableObject.CreateInstance<PoolList>(); string path="Assets/Scripts/Pool/poolList.asset"; AssetDatabase.CreateAsset(poolList, path); AssetDatabase.SaveAssets(); } poolList的建立要使用ScriptableObject中的方法,最後我們使用AssetDatabase中的方法將對象序列化儲存為asset檔案,路徑必須項目路徑開始否則會報錯。
五.建立PoolManager管理對象池
public class PoolManager { private PoolManager _instance; public PoolManager Instance { get { if (_instance == null) _instance = new PoolManager(); return _instance; } } private const string poolConfigurePath = "poolList"; private Dictionary<string, GameObjectPool> poolDic; private PoolManager() { PoolList poolList = Resources.Load<PoolList>(poolConfigurePath); poolDic=new Dictionary<string,GameObjectPool>(); foreach (GameObjectPool item in poolList.poolList) { poolDic.Add(item.name, item); } } public GameObject GetInst(string poolName) { GameObjectPool pool; if (poolDic.TryGetValue(poolName, out pool)) return pool.GetInst(); Debug.LogWarning("pool:" + poolName + "is not exist!"); return null; }
public void Init()
{ }
}
代碼很簡單,作為管理類一般都要做成單例模式,在建構函式中載入之前產生的配置表,使用字典結構來儲存每個對象池方便尋找,對外提供取對象的方法,最後的Init()方法用來初始化,因為我們的建構函式是私人的,所以在外界調用Instance的時候才會構造,如果在調用GetInst方法時候去建立會導致明顯的卡頓,所以只要在遊戲開始前調用一下Init這個空方法就可以了。
實際上對象池我們還可以繼續進行擴充,比如加上生命週期,讓一些我們很久沒有使用的對象在經過一段時間後自動銷毀掉來節省記憶體,等等在需要的時候可以繼續往深研究。