Unity,unity3d
孫廣東 2014.6.28
很早之前看到的外國文章,覺得不錯,分享一下, 對象池在AssetStore中也是有很多外掛程式的,但是有些重了,自己寫一個輕量的豈不是很好。
當你需要建立大量某種類型對象時,它可以方便地重新使用單個對象,而不是不斷地 建立/銷毀(操作會導致大量的記憶體回收)。此ObjectPool指令碼,產生和回收您的遊戲對象的對象池。
代碼:https://github.com/UnityPatterns/ObjectPool
http://unitypatterns.com/resource/objectpool/
特性:
?選擇性地池對象基於prefab類型
?簡單和運算式文法 對於 執行個體化和回收
?輕鬆地預先執行個體化對象,以防止運行時執行個體化
?搜尋和跟蹤所有產生/池子內的在情境中執行個體化的
怎麼使用?
通常情況下,當您執行個體化並銷毀prefabs的執行個體,您在運行時不斷建立新的對象和摧毀它們,這可能會導致運行時記憶體回收和偶爾的畫面播放速率下降。ObjectPool 可以防止這種,通過預先執行個體化,而不是被摧毀然後重建對象!
產生池子中的對象:
例如,如果我有能發射子彈對象的炮塔,我能建立 10 枚一模一樣的子彈對象並重新使用。子彈將永遠不會被銷毀,只是取消啟用、需要產生時重新啟用他們。
ObjectPool要做到這一點,你只要調用CreatePool() 產生指定Prefab的對象。
public class Turret : MonoBehaviour{ public Bullet bulletPrefab; void Start() { //Create a pool with 10 pre-instantiated bullets in it bulletPrefab.CreatePool(10); //Or you could also pre-instantiate none, and the system will instantiate them as it needs them bulletPrefab.CreatePool(); }}
現在你可以使用ObjectPool類中的Spawn() and Recycle() 來代替Instantiate() and Destroy()方法。例如,當搶發射子彈時,我產生子彈執行個體:
public class Turret : MonoBehaviour{ public Bullet bulletPrefab; public void ShootBullet() { //Spawn a bullet at my position with my rotation bulletPrefab.Spawn(transform.position, transform.rotation); }}
當你想要回收這個執行個體,在你想要消失的組件或者對象上調用Recycle()函數。 當子彈發生碰撞時,我們將回收它。
public class Bullet : MonoBehaviour{ void OnCollisionEnter(Collider other) { //De-activate the object and return it to the spawn pool gameObject.Recycle(); //You can also use this: //this.Recycle(); }}
函數Spawn()被建立的對象的引用, 所以你能夠儲存這個對象或者調用它的其他方法. 這個函數不像Unity的 Instantiate(), 你不需要強制類型轉換得到 GameObject or Component.
小心用回收的對象!
現在,您的對象正在被回收和重新使用,你必須要小心,因為如果您的執行個體有任何變數被改變,您必須手動重設它們。你可以通過使用Unity提供的的 OnEnable() 和 OnDisable() 函數,只要您的執行個體使用spawned or recycled函數將會觸發OnEnable() 和 OnDisable()。
例如,這是不正確的:
public class Bullet : MonoBehaviour{ public float travelDuration; float timer = 0; //Only gets set to zero once! void Update() { timer += Time.deltaTime; if (timer >= travelDuration) { gameObject.Recycle(); } }}
為什麼不對呢?因為我們的timer變數計數,但永遠不會返回到零!所以當回收並在此使用時,它已經不是最開始的狀態了。我們可以很容易解決這個問題:
public class Bullet : MonoBehaviour{ public float travelDuration; float timer; void OnEnable() { //Correct! Now timer resets every single time: timer = 0; } void Update() { timer += Time.deltaTime; if (timer >= travelDuration) { gameObject.Recycle(); } }}
現在我們的子彈正確重設他的timer變數。
你能通過對象引用預製體,在以前是不能的
GameObject現在有組件的擴充方法
InitialPoolSize 參數已添加到 CreatePool()函數總,並告訴它要預先執行個體化多少的對象,這些都是最初被隱藏和延遲產生的。
您還可以將 ObjectPool 附加到一個遊戲對象,通過inspector 設定要 預先執行個體化 的預製體
增益集函數已經添加了用於搜尋/統計 執行個體對象
如果你想要 RecycleAll 要使用衍生類別型,然後更改這:
var active = instance.prefabLookup.Keys.Where(p => p.GetType() == typeof(T).ToList();
to:
var active = instance.prefabLookup.Keys.Where(p => p is T).ToList();
也適用於 GetAllOfType 的類似的變化
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。