目錄
一. 什么是對(duì)象池
二、創(chuàng)建對(duì)象池
1、Stack
①Stack類
<1>構(gòu)造函數(shù)
<2>屬性
<3>方法
②Stack對(duì)象池
2、Queue
①Q(mào)ueue類
<1>構(gòu)造函數(shù)
<2>屬性
<3>方法
②Queue對(duì)象池
3.Unity官方對(duì)象池
①Object Pool類
<1>構(gòu)造函數(shù)
<2>屬性
<3>方法
②Object Pool對(duì)象池
一. 什么是對(duì)象池
顧名思義就是一定數(shù)量的已經(jīng)創(chuàng)建好的對(duì)象(Object)的集合。當(dāng)需要?jiǎng)?chuàng)建對(duì)象時(shí),先在池子中獲取,如果池子中沒(méi)有符合條件的對(duì)象,再進(jìn)行創(chuàng)建新對(duì)象,同樣,當(dāng)對(duì)象需要銷毀時(shí),不做真正的銷毀,而是將其setActive(false),并存入池子中,這樣就避免了大量對(duì)象的創(chuàng)建。
好處:降低性能,減少反復(fù)生成和摧毀產(chǎn)生的大量GC。
壞處:
①回收過(guò)程復(fù)雜度增加,在下次使用的同時(shí),需要清空回收前的數(shù)據(jù)。
②生命周期比其他的對(duì)象較長(zhǎng)。
二、創(chuàng)建對(duì)象池
下面提供三種方法,一種是Stack棧,一種是Queue隊(duì)列以及Unity官方封裝的對(duì)象池。
1、Stack
在開始之前我們需要了解Stack是什么,可以將他看成一個(gè)可以什么都裝的容器,特點(diǎn)是后進(jìn)先出,什么意思呢,就像我們上下樓一樣,當(dāng)我們從1樓走上5樓的時(shí)候,我們是從5樓走下來(lái),而不是從1樓走下來(lái)。舉個(gè)“Hello World? ! ”的例子:
進(jìn)棧:
? ? ?
? ? ? ?
? ? ?? ? ? ?
出棧:
可以看見是后進(jìn)先出的。
①Stack類
<1>構(gòu)造函數(shù)
Stack():初始化Stack類的新實(shí)例,該實(shí)例為空并且具有默認(rèn)初始容量。
Stack(ICollection):初始化Stack類的新實(shí)例,該實(shí)例包含從指定集合復(fù)制的元素并且具有與所復(fù)制的元素?cái)?shù)相同的初始容量。
Stack(Int32):初始化Stack類的新實(shí)例,該實(shí)例為空并且具有指定的初始容量或默認(rèn)初始容量(這兩個(gè)容量中的較大者)。
<2>屬性
Count:獲取 Stack 中包含的元素?cái)?shù)。
IsSynchronized:獲取一個(gè)值,該值指示是否同步對(duì) Stack 的訪問(wèn)(線程安全)
SyncRoot:獲取可用于同步對(duì) Stack 的訪問(wèn)的對(duì)象。
<3>方法
紅色為常用方法:
Clear():從 Stack 中移除所有對(duì)象。
Clone():創(chuàng)建 Stack 的淺表副本。
Contains(Object):確定某元素是否在 Stack 中。
CopyTo(Array, Int32):從指定的數(shù)組索引處開始,將 Stack 復(fù)制到現(xiàn)有的一維 Array中。
Equals(Object):確定指定對(duì)象是否等于當(dāng)前對(duì)象。(繼承自 Object)
GetEnumerator():返回IEnumerator 的 Stack。
GetHashCode():作為默認(rèn)哈希函數(shù)。(繼承自 Object)
GetType():獲取當(dāng)前實(shí)例的 Type。(繼承自 Object)
MemberwiseClone():創(chuàng)建當(dāng)前 Object 的淺表副本。(繼承自 Object)
Peek():返回位于 Stack 頂部的對(duì)象但不將其移除。
Pop():刪除并返回 Stack 頂部的對(duì)象。
Push(Object):在Stack的頂部插入一個(gè)對(duì)象。
Synchronized(Stack):返回Stack的同步(線程安全)包裝。
ToArray():將 Stack 復(fù)制到新數(shù)組中。
ToString():返回表示當(dāng)前對(duì)象的字符串。(繼承自 Object)
②Stack對(duì)象池
首先寫一個(gè)對(duì)象池接口,畢竟可能我們有著不同的對(duì)象池,直接寫泛型的對(duì)象池,寫個(gè)委托,可以我們?cè)诨厥找约矮@取的時(shí)候,還需要處理其他的邏輯。
public interface IPool<T>
{
public delegate void CallBack();
void Get(CallBack callBack = null);
void Release(T gameobject, CallBack callBack = null);
void Create();
void Destroy(T gameobject);
}
然后我們寫一個(gè)BasePool來(lái)實(shí)現(xiàn)IPool接口,其實(shí)看起來(lái)也不是很難,就是對(duì)Stack的進(jìn)棧以及出棧做調(diào)整。
using System.Collections.Generic;
using UnityEngine;
public class BasePool : IPool<GameObject>
{
protected GameObject insGameObject;
public Stack<GameObject> pool;
//創(chuàng)建一個(gè)帶參數(shù)的構(gòu)造函數(shù)是因?yàn)槲业捻?xiàng)目里面有需求,可以根據(jù)直接的需求改或者不要
public BasePool(GameObject gameObject)
{
this.insGameObject = gameObject;
pool = new Stack<GameObject>();
}
public virtual void Create()
{
GameObject go = GameObject.Instantiate(insGameObject);
/*
* 添加對(duì)應(yīng)的組件....
*/
pool.Push(go);
pool.Pop();
}
public virtual void Destroy(GameObject gameobject)
{
}
public virtual void Get(IPool<GameObject>.CallBack callBack = null)
{
if (pool.Count == 0)
{
//當(dāng)pool沒(méi)有東西的時(shí)候就直接創(chuàng)建一個(gè)
Create();
}
else
{
//將物體重新拿出來(lái)
GameObject go = pool.Pop();
/*
* 添加對(duì)應(yīng)的組件....
*/
go.SetActive(true);
}
//處理邏輯
if (callBack != null)
{
callBack();
}
}
public virtual void Release(GameObject gameobject, IPool<GameObject>.CallBack callBack = null)
{
//回收的時(shí)候需要做什么
if (callBack != null)
{
callBack();
}
gameobject.SetActive(false);
pool.Push(gameobject);
}
}
?其實(shí)對(duì)于上面來(lái)說(shuō)已經(jīng)是簡(jiǎn)單的弄好了,下面的是怎么使用,創(chuàng)建一個(gè)TestPool繼承BasePool,
using UnityEngine;
public class TestPool : BasePool
{
public TestPool(GameObject gameObject) : base(gameObject)
{
}
public override void Get(IPool<GameObject>.CallBack callBack = null)
{
base.Get(callBack);
}
public override void Release(GameObject gameobject, IPool<GameObject>.CallBack callBack = null)
{
base.Release(gameobject, callBack);
}
public override void Destroy(GameObject gameobject)
{
base.Destroy(gameobject);
}
public override void Create()
{
base.Create();
}
}
?在你需要使用到的地方,按照下方的樣子就可以運(yùn)作起來(lái)了,具體的業(yè)務(wù)要求還是得你自己具體的實(shí)現(xiàn)。
public void PoolTest()
{
//實(shí)例化一個(gè)對(duì)象池
TestPool testPool = new TestPool(/*傳入需要生成的GameObject*/);
testPool.Get();
/*傳入需要生成的GameObject,也可以選著是否重置Game Object上的組件以及重置數(shù)據(jù)*/
testPool.Release(gameObject,test);
}
private void test()
{
/*
處理邏輯
*/
}
2、Queue
和Stack不同的是,Queue特點(diǎn)是先進(jìn)先出,什么意思呢,我們排隊(duì)買早餐,先排隊(duì)的人可以先買到早餐然后先離開,舉個(gè)“Hello World? ! ”的例子:
進(jìn)列:
?? ? ?
? ? ? ?
? ? ?? ? ? ?
出列:
①Q(mào)ueue類
<1>構(gòu)造函數(shù)
Queue():初始化Queue類的新實(shí)例,該實(shí)例為空,具有默認(rèn)初始容量并使用默認(rèn)增長(zhǎng)因子。
Queue(ICollection):初始化 Queue 類的新實(shí)例,該實(shí)例包含從指定集合復(fù)制的元素,具有與所復(fù)制的元素?cái)?shù)相同的初始容量并使用默認(rèn)增長(zhǎng)因子。
Queue(Int32):初始化 Queue 類的新實(shí)例,該實(shí)例為空,具有指定的初始容量并使用默認(rèn)增長(zhǎng)因子。
Queue(Int32,Single):初始化Queue類的新實(shí)例,該實(shí)例為空,具有指定的初始容量并使用指定的增長(zhǎng)因子。
<2>屬性
Count:獲取Queue中包含的元素?cái)?shù)。
IsSynchronized:獲取一個(gè)值,該值指示是否同步對(duì)Queue的訪問(wèn)(線程安全)
SyncRoot:獲取可用于同步對(duì)Queue的訪問(wèn)的對(duì)象。
<3>方法
紅色為常用方法:
Clear():從Queue中移除所有對(duì)象。
Clone():創(chuàng)建 Queue 的淺表副本。
Contains(Object):確定某元素是否在Queue中。
CopyTo(Array, Int32):從指定數(shù)組索引開始將 Queue 元素復(fù)制到現(xiàn)有一維 Array 中。
Dequeue():移除并返回位于Queue開始處的對(duì)象。
Enqueue(Object):將對(duì)象添加到Queue的結(jié)尾處。
Equals(Object):確定指定對(duì)象是否等于當(dāng)前對(duì)象。(繼承自 Object)
GetEnumerator():返回循環(huán)訪問(wèn) Queue 的枚舉數(shù)。GetHashCode)作為默認(rèn)哈希函數(shù)。(繼承自 Object)
GetType():獲取當(dāng)前實(shí)例的 Type。(繼承自O(shè)bject)
MemberwiseClone():創(chuàng)建當(dāng)前 Object 的淺表副本。(繼承自 Object)
Peek():返回位于 Queue 開始處的對(duì)象但不將其移除。
Synchronized(Queue):返回將包裝原始隊(duì)列并且是線程安全的新的 Queue。
ToArray():將 Queue 元素復(fù)制到新數(shù)組。
ToString():返回表示當(dāng)前對(duì)象的字符串。(繼承自 Object)
TrimToSize():將容量設(shè)置為 Queue 中元素的實(shí)際數(shù)目。
②Queue對(duì)象池
其實(shí)關(guān)于Queue寫的對(duì)象池和Stack寫的對(duì)象池沒(méi)什么區(qū)別只不過(guò)是使用的類不一樣。創(chuàng)建一個(gè)BaseQueuePool的Queue類的對(duì)象池。
using System.Collections.Generic;
using UnityEngine;
public class BaseQueuePool : IPool<GameObject>
{
protected GameObject insGameObject;
public Queue<GameObject> pool;
public void Create()
{
GameObject go = GameObject.Instantiate(insGameObject);
go.SetActive(true);
pool.Enqueue(go);
pool.Dequeue();
}
public void Destroy(GameObject gameobject)
{
}
public void Get(IPool<GameObject>.CallBack callBack = null)
{
if (pool.Count == 0)
{
//當(dāng)pool沒(méi)有東西的時(shí)候就直接創(chuàng)建一個(gè)
Create();
}
else
{
//將物體重新拿出來(lái)
GameObject go = pool.Dequeue();
go.SetActive(true);
}
if (callBack != null)
{
callBack();
}
}
public void Release(GameObject gameobject, IPool<GameObject>.CallBack callBack = null)
{
//回收的時(shí)候需要做什么
if (callBack != null)
{
callBack();
}
gameobject.SetActive(false);
pool.Enqueue(gameobject);
}
}
然后使用方法是和上面用Stack類寫的用法一樣。
3.Unity官方對(duì)象池
當(dāng)然,不想自己寫對(duì)象池也是可以的,Unity為我們封裝好對(duì)象池。
①Object Pool類
<1>構(gòu)造函數(shù)
public?ObjectPool<T0>(Func<T>?createFunc, Action<T>?actionOnGet, Action<T>?actionOnRelease, Action<T>?actionOnDestroy, bool?collectionCheck, int?defaultCapacity, int?maxSize);
構(gòu)造函數(shù)需要傳入7個(gè)參數(shù),它們按順序分別是:
createFunc:用于在池為空時(shí)創(chuàng)建新實(shí)例。在大多數(shù)情況下,這只是()=> new T()。
actionOnGet:從池中獲取實(shí)例時(shí)調(diào)用。
actionOnRelease:當(dāng)實(shí)例返回到池時(shí)調(diào)用。這可用于清理或禁用實(shí)例。
actionOnDestroy:當(dāng)由于池達(dá)到最大大小而無(wú)法將元素返回到池時(shí)調(diào)用。
collectionCheck:將實(shí)例返回到池時(shí)執(zhí)行集合檢查。如果實(shí)例已經(jīng)在池中,則會(huì)拋出異常。集合檢查只在編輯器。
defaultCapacity:創(chuàng)建堆棧時(shí)使用的默認(rèn)容量。
maxSize:池的最大大小。當(dāng)池達(dá)到最大大小時(shí),返回到池中的任何其他實(shí)例都將被忽略,并可以被垃圾收集。這可以用來(lái)防止池增長(zhǎng)到非常大的規(guī)模
<2>屬性
CountActive:池已創(chuàng)建但當(dāng)前正在使用且尚未返回的對(duì)象數(shù)。
CountAll:活動(dòng)和非活動(dòng)對(duì)象的總數(shù)。
CountInactive:池中當(dāng)前可用的對(duì)象數(shù)。
<3>方法
Clear:刪除所有池項(xiàng)。如果池包含destroy回調(diào)函數(shù),那么它將被池中的每個(gè)項(xiàng)目調(diào)用。
Dispose:刪除所有池項(xiàng)。如果池包含destroy回調(diào)函數(shù),那么它將被池中的每個(gè)項(xiàng)目調(diào)用。
Get:從池中獲取實(shí)例。如果池為空,則將創(chuàng)建一個(gè)新實(shí)例。
Release:將實(shí)例返回到池中。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-811200.html
②Object Pool對(duì)象池
using UnityEngine;
using UnityEngine.Pool;
public class UnityPool : MonoBehaviour
{
private ObjectPool<GameObject> pool;
//池子初始化大小
int poolSize = 20;
//池子最大數(shù)量
int poolMaxSize = 100;
private void Start()
{
pool = new ObjectPool<GameObject>(OnCreate, OnGet, OnRelease, OnDestroy, true, poolSize, poolMaxSize);
}
/// <summary>
/// 實(shí)例化對(duì)象
/// </summary>
/// <returns></returns>
private GameObject OnCreate()
{
/*實(shí)例化需要使用對(duì)象池的物體*/
GameObject go = Instantiate();
/*
添加需要的組件
或者其他邏輯
*/
return go;
}
/// <summary>
/// 獲取對(duì)象池內(nèi)的實(shí)例
/// </summary>
/// <param name="object"></param>
private void OnGet(GameObject obj)
{
obj.SetActive(true);
}
/// <summary>
/// 回收實(shí)例到對(duì)象池
/// </summary>
/// <param name="obj"></param>
private void OnRelease(GameObject obj)
{
/*
* 回收前需要的邏輯
*/
obj.SetActive(false);
}
/// <summary>
/// 銷毀實(shí)例
/// </summary>
/// <param name="obj"></param>
private void OnDestroy(GameObject obj)
{
Destroy(obj);
}
}
?使用方法也是和上方Stack寫的對(duì)象池一樣。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-811200.html
到了這里,關(guān)于Unity對(duì)象池和自寫對(duì)象池的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!