码迷,mamicode.com
首页 > 编程语言 > 详细

Unity ----- 对象池GameObjectPool

时间:2015-07-03 10:38:32      阅读:107      评论:0      收藏:0      [点我收藏+]

标签:unity3d   unity   c#   

孙广东 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 的类似的变化






版权声明:本文为博主原创文章,未经博主允许不得转载。

Unity ----- 对象池GameObjectPool

标签:unity3d   unity   c#   

原文地址:http://blog.csdn.net/u010019717/article/details/46674491

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!