• Unity ----- 对象池GameObjectPool


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






  • 相关阅读:
    2019.1.5JavaScript
    SQL常用删改增语句
    PHP连接数据库
    PHP数组函数
    PHP字符串常用函数
    PHP 类型判断方法
    jQuery效果
    jQuery特性
    倒计时
    判断浏览器及其内核
  • 原文地址:https://www.cnblogs.com/yjbjingcha/p/6878355.html
Copyright © 2020-2023  润新知