问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

Unity开发中对象池设计与使用详解

创作时间:
作者:
@小白创作中心

Unity开发中对象池设计与使用详解

引用
CSDN
1.
https://blog.csdn.net/2301_79022588/article/details/146284488

在Unity开发中,对象池是一种常用的优化技术,用于管理游戏中的对象,避免频繁创建和销毁对象带来的性能开销。本文将详细介绍对象池的设计原理和具体实现方法,帮助开发者更好地理解和应用这一技术。

设计目的

为了避免频繁创建和销毁对象(例如 UI 元素、事件对象等)带来的内存分配和垃圾回收压力,可以使用对象池来管理对象来提高游戏的性能,避免游戏卡顿。

代码实现

public interface IRecycle
{
    /// <summary>
    /// 回池必须调用的接口
    /// </summary>
    public void OnRecycle();
    /// <summary>
    /// 初始化接口
    /// </summary>
    public void OnFetch();
}

public class CacheObjectMgr : Singleton<CacheObjectMgr>
{
    private Dictionary<Type, Queue<IRecycle>> m_Gos;

    protected override void OnInit()
    {
        base.OnInit();
        m_Gos = new Dictionary<Type, Queue<IRecycle>>();
    }

    public T Fetch<T>() where T : class, IRecycle, new()
    {
        IRecycle obj = null;
        Queue<IRecycle> pool = _GetPool(typeof(T));
        if (pool.Count > 0)
        {
            obj = pool.Dequeue();
        }
        else
        {
            obj = new T();
        }
        obj.OnFetch();
        return obj as T;
    }

    public void Recycle(IRecycle go)
    {
        if (go != null)
        {
            go.OnRecycle();
            _GetPool(go.GetType()).Enqueue(go);
        }
    }

    private Queue<IRecycle> _GetPool(Type type)
    {
        Queue<IRecycle> pool = null;
        if (!m_Gos.TryGetValue(type, out pool))
        {
            pool = new Queue<IRecycle>();
            m_Gos.Add(type, pool);
        }
        return pool;
    }
}

代码分析

  • 字典存储结构:使用 Type 作为键,存储每种类型对应的对象池(队列)。这样不同类型的对象可以分开管理,且在回收和取用时无需强制转换。

  • 对象池的设计:每个队列中存储的都是 IRecycle 类型的对象。由于 C# 支持接口的多态性,只要对象实现了 IRecycle 接口,就可以存入该队列中,而不需要关心具体的实现类型。

  • 这个接口定义了两个关键方法

  • OnFetch():在对象从池中取出时调用,用于执行初始化工作(例如重置状态、注册事件等)。

  • OnRecycle():在对象回收前调用,用于清理或重置对象状态(例如注销事件、释放资源等)。

  • Fetch 逻辑:方法约束:where T : class, IRecycle, new() 确保了被管理的对象必须实现 IRecycle 接口,并且可以通过无参构造函数创建。

  • 获取对象的方式

    1. 通过 _GetPool(typeof(T)) 获取对应类型的对象池(如果不存在则创建新的队列)。
    2. 判断池中是否有可用对象:如果有则调用 Dequeue 取出,否则通过 new T() 创建新对象。
    3. 调用对象的 OnFetch() 方法完成初始化操作(例如注册事件、设置状态等)。
    4. 返回对象,并通过 as T 进行类型转换。

这种实现方式确保了在每次从池中取出对象前,都能通过 OnFetch 方法对对象进行了必要的初始化,保证对象处于可用状态。

  • 该方法通过传入对象的类型来获取或创建对应的队列。

  • 获取对象的方式:

    1. 判断是否存在该类型的对象池,如果不存在就创建该类型的对象池并将其添加到字典中。
    2. 如果存在就获取该类型的对象池。

回收对象的方法

该方法在对象使用完毕后,进行调用 Recycle 方法然后将对象放回池中。

  1. 判断对象是否为空
  2. 调用对象的 OnRecycle() 方法:此方法通常用于清理、解除事件注册、释放使用过的资源等,这样可以确保对象在下次取用前处于一个全新的状态。
  3. 然后根据对象类型,调用 _GetPool(go.GetType()) 获取对应的队列,然后使用 Enqueue 将对象加入队列。

示例演示

关键步骤:

  • 在类中去实现 IRecycle 这个接口,实现这个接口就要去实现接口中所声明的所有方法。
  • 在通过 Fetch 方法创建对象时会调用该对象中的 OnFetch() 进行初始化。
  • 回收方法实现:
  • 在事件结束后调用 OnRelease 进行回收,调用该方法会通过 Recycle 先调用 OnRecycle() 方法,进行比如:清理状态、注销事件和释放使用过的资源等。然后将对象重新放入对象池中,等待下次复用。

总结

通过这种方式去管理游戏中的对象,可以减少了对象频繁创建的性能开销,进而避免游戏卡顿。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号