對象池在Unity3D中是極為重要的技術(shù),在遇到需要大量重復(fù)創(chuàng)建、銷毀的對象時,對象池可以將其存放入池中,反復(fù)利用,從而盡可能的重復(fù)使用內(nèi)存中駐留的資源。
對象池的典型用法就是射擊游戲中的子彈。在不使用對象池時,子彈的“一生”是這樣的:創(chuàng)建→產(chǎn)生作用→銷毀;而使用對象池后,子彈的“一生”是這樣的:從對象池中取出使用→產(chǎn)生作用→存放進對象池→從對象池中取出使用···
顯而易見的,該方法能避免重復(fù)對象的創(chuàng)建、銷毀過程,節(jié)省內(nèi)存空間的使用。以下為一個子彈對象池的大致創(chuàng)建過程
首先是對象池創(chuàng)建
//prefabPool = new PrefabPool(Resources.Load<Transform>("xxx"));加載本地預(yù)制
//prefabPool.cullDespawned = true;自動清理對象池
public static BulletPool bullet;//該部分用于初始化此對象池的配置
public GameObject bulletObj;
public int pooledAmount = 5;//初始化對象池中對象數(shù)量
public bool lockPoolSize = false;//取消鎖定對象池大小
private List<GameObject> pooledObjects;//創(chuàng)建對象池鏈表
private int currentIndex = 0;
void Awake()
{
bullet = this;//實例化對象池
}
在start()中初始化對象池鏈表
void Start()
{
pooledObjects = new List<GameObject>();
for (int i = 0; i < pooledAmount; ++i)
{
GameObject obj = Instantiate(bulletObj);//創(chuàng)建子彈對象
obj.SetActive(false);//將子彈對象的激活狀態(tài)Active設(shè)置為false
pooledObjects.Add(obj);//將子彈存放入對象池中
}
}
調(diào)用該子彈對象池中的可用子彈
public GameObject GetPooledObject()
{
for (int i = 0; i < pooledObjects.Count; ++i)//遍歷對象池以尋找可用子彈
{
//從上一次調(diào)用的子彈的下一個開始尋找
//例如上一次發(fā)射的子彈是對象池中序號為2的子彈,則本次調(diào)用對象池中子彈時從3開始檢查是否可用
int temI = (currentIndex + i) % pooledObjects.Count;
if (!pooledObjects[temI].activeInHierarchy)//檢查該對象的Active狀態(tài)
{
currentIndex = (temI + 1) % pooledObjects.Count;
return pooledObjects[temI];//如果Active為false則返回調(diào)用該對象
}
}
if(!lockPoolSize)//若沒有false狀態(tài)的子彈供我們使用,則生成新的對象并加入對象池
{
GameObject obj = Instantiate(bulletObj);
pooledObjects.Add(obj);
return obj;
}
return null;
}
在對象池中尋找可用對象時,最初只通過遍歷進行地毯式搜索。在實際使用時,經(jīng)過頻繁的調(diào)用后,會產(chǎn)生略微影響體驗的卡頓,一開始以為是對象過多,機器的機能限制,后來查看到了一篇文章,指明了這一問題產(chǎn)生的原因。
在尋找可用對象時,如果每次遍歷都從頭開始,如果對象池極大,且先前的對象仍然處于激活狀態(tài),我們將需要大量時間用來無謂的遍歷,導(dǎo)致卡頓。因此,在代碼中記錄之前使用的對象序號,并從序號記錄的下一個對象開始查找可用對象。
這一方法可以極大程度改善因遍歷而浪費的機能、時間,對游戲性能進行優(yōu)化。
對象池是Unity中對性能優(yōu)化極為重要的技術(shù)。在CPU、內(nèi)存并非充滿"Power"的情況下,對象池是讓硬件的無謂重復(fù)盡可能降到最低,使有限的硬件資源用在最需要的地方,達到優(yōu)化效果。
個人看來,對象池最大的優(yōu)點在于復(fù)用、預(yù)載這兩方面。復(fù)用是對象池的典型特征、靈魂所在;而預(yù)載方面,作為玩家試想一下,玩家是愿意在加載界面多花1秒鐘,還是在激烈戰(zhàn)斗時突然卡頓0.1秒。結(jié)果是顯而易見的。