UniRx-unirx中的對象池
一、對象池模式
1.概念
定義一個池對象,其包含了一組可重用對象。 其中每個可重用對象都支持查詢“使用中”狀態,說明它是不是“正在使用”。 池被初始化時,它就創建了整個對象集合(通常使用一次連續的分配),然後初始化所有對象到“不在使用中”狀態。
當你需要新對象,向池子要一個。 它找到一個可用對象,初始化爲“使用中”然後返回。 當對象不再被需要,它被設置回“不在使用中”。 通過這種方式,可以輕易地創建和銷燬對象而不必分配內存或其他資源。
2.優點
遊戲中會出現諸如子彈,粒子特效等大量的單一資源。頻繁的創建和銷燬會浪費很多性能並且產生大量的內存碎片。對象池模式放棄單獨地分配和釋放對象,從固定的池中重用對象,以提高性能和內存使用率。
3.何時使用
- 需要頻繁創建和銷燬對象。
- 對象大小相仿。
- 在堆上進行對象內存分配十分緩慢或者會導致內存碎片。
- 每個對象都封裝了像數據庫或者網絡連接這樣很昂貴又可以重用的資源。
4.注意
- 可以將創建對象和銷燬對象平緩的放到多個幀處理
- 動態的維護池子的大小
UniRx中的對象池使用
1.案例
1.1 prefab上腳本
using System;
using UniRx;
using UnityEngine;
using Random = UnityEngine.Random;
public class PoolObject : MonoBehaviour
{
public IObservable<Unit> AsyncAction()
{
var colorstream = Observable.Timer(TimeSpan.FromSeconds(0.2f));
colorstream.Subscribe(_ =>
{
GetComponent<Renderer>().material.color = Color.Lerp(Color.red, Color.blue, Random.Range(0.0f,1.0f));
});
var positiontream = Observable.Timer(TimeSpan.FromSeconds(0.2f));
positiontream.Subscribe(_ =>
{
transform.localPosition=Vector3.one*Random.Range(-5f,5f);
});
var unit = Observable.ReturnUnit();
var allStream = Observable.WhenAll(unit);
allStream.Subscribe(_ =>
{
Debug.Log("QAQ");
});
return Observable.ReturnUnit();
}
}
2.自定義對象池
using System;
using UniRx;
using UniRx.Toolkit;
using UnityEngine;
using Object = UnityEngine.Object;
using Random = UnityEngine.Random;
public class UniRxObjectPool : ObjectPool<PoolObject>
{
private GameObject _prefab;
public UniRxObjectPool(GameObject prefab)
{
this._prefab = prefab;
}
protected override PoolObject CreateInstance()
{
var gameObj = Object.Instantiate(_prefab);
return gameObj.GetComponent<PoolObject>();
}
protected override void OnBeforeRent(PoolObject instance)
{
base.OnBeforeRent(instance);
Debug.Log($"從池子中取出:{instance.name}");
}
// 在對象返回到池子裏面之前回調
protected override void OnBeforeReturn(PoolObject instance)
{
base.OnBeforeReturn(instance);
Debug.Log($" 返回 {instance} 到池子裏面");
}
// 在對象從池子裏面移除回調
protected override void OnClear(PoolObject instance)
{
base.OnClear(instance);
Debug.Log($"從池子裏面移除 {instance}");
}
}
3.對象池調用
using System;
using UniRx;
using UnityEngine;
using UnityEngine.UI;
public class No11_ObjectPool : MonoBehaviour
{
[SerializeField]
private GameObject mPoolPrefab;
[SerializeField]
private Button mBtnSpawn;
[SerializeField]
private Button mBtnShrink;
[SerializeField]
private Button mBtnClear;
void Start()
{
UniRxObjectPool pool = new UniRxObjectPool(mPoolPrefab);
mBtnSpawn.OnClickAsObservable().Subscribe(_ =>
{
for (int i = 0; i < 5; i++)
{
//從池中獲取實例,出棧
var poolObj = pool.Rent();
poolObj.AsyncAction().Subscribe(next =>
{
Debug.Log("mult thread run");
});
//根據對象創建的頻率來擴張池子大小
Observable.TimerFrame(300).Subscribe(f =>
{
//回收對象到池子
pool.Return(poolObj);
});
}
});
mBtnShrink.OnClickAsObservable().Subscribe(_ =>
{
// 手動回收對象池子, 第一個參數是回收比例,第二個參數是保存最小數量
//pool.Shrink(0.6f, 1);
// 自動回收對象池子,3秒檢查一次進行回收,銷燬實例,縮小池子大小,保持最小數
pool.StartShrinkTimer(TimeSpan.FromSeconds(3f), 0.6f, 2);
});
mBtnClear.OnClickAsObservable().Subscribe(_ =>
{
//清理對象池,destroy所有對象
pool.Clear();
});
}
}