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