[Unity3D教程]Unity中如何编写对象重用池机制

来源:互联网 发布:拓普康332n软件 编辑:程序博客网 时间:2024/05/22 07:42

[Unity3D教程]Unity中如何编写对象重用池机制

对象重用池的概念其实非常简单:创建使用后的对象不会直接销毁,而是存储在一个池子中,当需要时在可在池子中拿出再供使用。

对象池的最重要的特性,也就是对象池设计模式的本质是允许我们获取一个“新的”对象而不管它真的是一个新的对象还是循环使用的对象。

对象重用池是典型“空间换时间”案例。通过减少CPU调用系统调用时的资源消耗,转为对内存的长期占用,进而达到提升“处理速度”的效果。也就是说:对象重用池是对CUP的优化,而不是对内存的优化策略(反而是增加负担了呢)。

对象重用池机制在各个语言中都普遍存在,有些语言甚至将重用池机制封装到了框架底层,比如iOS中的TableViewCell的重用机制。在Unity中的用户自定义对象并没有现成类来提供重用管理,这个功能需要我们自己编写。

对象重用池的方案有非常多的成熟框架供我们使用,甚至三言两语就能勾勒出一幅重用池:


#使用堆栈模拟一个简单的对象重用池#

  

使用方法:


当然, 上述代码只能出现在演示Demo中, 它实在是太简单了。事实上,如果你搜索下用Unity实现的对象池类库,你会发现其中很多是相当复杂的。我们先来分析下一个合格的对象池应该具备哪些优秀品质:

• 对象进入对象池之时,应该提供接口事件,通知用户该事件。

• 从池子中拿出的对象时,应该提供接口事件,用户可以在方法内对该对象进行操作,比如重置、刷新数据。

• 能够管理多种对象。

• 能够提供清理池子的接口,甚至提供定期自动清理策略。

• 某些类型的资源是很珍贵的(如数据库连接),池需要显示上限并提供一个针对分配对象失败的安全措施;

• 对于需要长期持有的资源,如网络连接、数据库连接等资源,需要提供分配失败的安全措施。

• 线程安全的。

 

在此提供一种实现思路:

• 面向用户的ObjectPoolCtrl(对象池管理类)类:

该类直接与用户交互且负责管理多个对象池子.

• 能够进入池子的对象需要遵循的协议IReuse

• 能够进入池子的对象基类ReuseObject

• 池子类SubPool,真正妇科管理对象

 

 关系示意图:

 

接口代码:

public interface IReuse {
    void Spawn();
    void UnSpawn();
}

 

基类代:

using UnityEngine;
public abstract class ReuseObject : MonoBehaviourIReuse {
    // 所有类的基类想要入池子的象不要在MonoBehaviour
    // 而是要承此类.
    public abstract void Spawn();
    public abstract void UnSpawn();
}

 

负责和用户交互的象池管理类:

using UnityEngine;
using System.Collections.Generic;
public class ObjectPoolCtrl : MonoSingleton<ObjectPoolCtrl> {

    #region 字段
    // 总池子
    Dictionary<stringSubPool> m_pools = new Dictionary<stringSubPool>();
    #endregion
    #region 面向用户的方法


    public GameObject Spawn(string name) {
        SubPool subPool;
        // 如果总的池子中含有子池子的名
        if (m_pools.ContainsKey(name)) {
            RegisterSubPools(name);
        }
        // 将刚刚创建好的子池子放入到大池子中
        subPool = m_pools[name];
        return subPool.Spawn();
    }

    private void RegisterSubPools(string name) {
        GameObject prefab = ResourcesMgrBase.Instance.Load<GameObject>(name);
        SubPool subPool = new SubPool(prefab);
        m_pools.Add(subPool.Name, subPool);
    }
    private void UnSpawn(GameObject obj) {
        foreach (SubPool pool in m_pools.Values) {
            if (pool.Contains(obj)) { // 里是比的两个象完全相等.
                pool.UnSpawn(obj);
                break;
            }
        }
    }
    // 清空所有池子的方法
    private void UnSpawnALl() {
        foreach (SubPool pool in m_pools.Values) {
            pool.UnSpawnAll();
        }
    }
    #endregion
}

 

池子对象:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class SubPool {
    #region 字段
    // list表存放池子的所有
    List<GameObject> m_subPool = new List<GameObject>();
    // 池子中设体的设体类型.
    GameObject m_prefab;
    #endregion

    #region 属性
    // 前池子的名
    public string Name {
        get {
            return m_prefab.name;
        }
    }
    #endregion

    #region 构造方法
    // 外部可以通过传入一个设体构造一个池子.
    // 但是池子是什么建的呢?
    // 个方法也new一个池子啊.
    public SubPool (GameObject prefab) {
        m_prefab = prefab;
    }

    public GameObject Spawn() {
        GameObject obj = null;
        foreach (GameObject go in m_subPool) {
            if (go.active == false) {
                obj = go;
                break;
            }
        }

        if (obj == null) {
            obj = GameObject.Instantiate(m_prefab) as GameObject;
            m_subPool.Add(obj);
        }

        // 从池子出就要激活状态设置激活了.
        obj.SetActive(true);
        // 取池子象中的接口方法如果有才.
        IReuse iReuse = obj.GetComponent<IReuse>();
        if (iReuse != null) {
            iReuse.Spawn();
        }
        return obj;
    }

    public void UnSpawn(GameObject obj) {
        if (m_subPool.Contains(obj)) {
            IReuse iReuse = obj.GetComponent<IReuse>();
            if (iReuse != null) {
                iReuse.UnSpawn();
            }
            obj.SetActive(false);
        }
    }

    public void UnSpawnAll() {
        foreach    (GameObject obj in m_subPool) {
            if (obj.activeSelf) {
                UnSpawn(obj);
            }
        }
    }

    public bool Contains(GameObject go) {
        return m_subPool.Contains(go);
    }
    #endregion
}


 欢迎到CSDN学院观看我的Unity3D开发视频教程http://edu.csdn.net/lecturer/lecturer_detail?lecturer_id=107

(权归蓝欧科技有限公司所有,任何单位或者个不可以私自转载,如果有需有,请于蓝欧科技有限公司相关部门联系)

(部分参考:原文地址: http://www.gamasutra.com/blogs/WendelinReich/20131127/203843/C_Memory_Management_for_Unity_Developers_part_3_of_3.php)

0 0