對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這個空方法就可以了。實際上對象池我們還可以繼續進行擴展,比如加上生命週期,讓一些我們很久沒有使用的對象在經過一段時間後自動銷燬掉來節省內存,等等在需要的時候可以繼續往深研究。