孙广东 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 的类似的变化
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/u010019717/article/details/46674491