孙广东 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变量计数。但永远不会返回到零!所以当回收并在此使用时,它已经不是最開始的状态了。
我们能够非常easy解决问题:
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 的相似的变化