Unity3D泛型对象池

Posted lihangppz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity3D泛型对象池相关的知识,希望对你有一定的参考价值。

  游戏开发中,不可避免的用到了对象池。如果一个对象频繁的创建、使用、销毁,就需要考虑用对象池。写之前简单搜了一下“unity 对象池”,大多数是对GameObject管理,或者自定义的一个父类。

  而且用到对象池的地方很多,被管理的对象种类也很多,可以是GameObject也可以是UIlabel,还可以是buff、特效、等等。都继承一个父类或者写多个对象池管理,显然是不合算的。

  各路大神应该都有自己的解决方案,我简单说一下泛型对象池。

  泛型对象池优点:

  1、避免了频繁的创建和消耗,这是用对象池的目的

  2、逻辑简单,即便是重构也花不了多少时间。

  3、适用性比较广泛,这是泛型的优点。

  缺点:项目里用了3年,也上线跑了1年多,还未发现明显缺点。

 

  百度上有很多关于泛型的文章,大神讲解的也很详细,我就不多说,我们平时用泛型还是比较多的,比如,List<int> test = new List<int>();其中<>包裹的int就是用了泛型。

  简单说一下思路。

  1、每个对象都去实现一个接口,同时这个接口也是泛型的约束。这个接口应该包括回收和清理,部分情况只有回收就可以满足。

  2、对象池本身应该要有上限,对象集合,当前可用,当前已用,获取对象,回收对象,清理所有对象。其中对象集合,有的用列表,有的用字典,这里用了栈(Stack)。

  下面展示每个功能的代码:

  1、对象接口:IObject

public interface IObject
{
    void Reset();
    void Cleanup();
}

  这里不用多说,回收Reset,清理Cleanup。其实功能相同,只不过清理的时候会有一个特殊操作,可以按需求写成一个。

  2、对象池管理:ObjectPool

using System.Collections.Generic;
public static class ObjectPool<T> where T : IObject, new()
{
    private static int _maxCount = 50;
    private static Stack<T> pool;
    private static int totalCreated;
    static ObjectPool()
    {
        pool = new Stack<T>();
    }

    /// <summary>
    /// 回收对象
    /// </summary>
    /// <param name="obj"></param>
    public static void Recycle(T obj)
    {
        obj.Cleanup();
        if (pool.Count < maxCount)
        {
            pool.Push(obj);
        }
    }

    public static int maxCount
    {
        get
        {
            return _maxCount;
        }
        set
        {
            _maxCount = value;
        }
    }

    /// <summary>
    /// 总创建数
    /// </summary>
    /// <returns></returns>
    public static int GetTotalCreated()
    {
        return totalCreated;
    }

    /// <summary>
    /// 当前可用大小
    /// </summary>
    /// <returns></returns>
    public static int GetSize()
    {
        return pool.Count;
    }

    public static T GetObj()
    {
        T result;
        if (pool.Count > 0)
        {
            result = pool.Pop();
        }
        else
        {
            result = new T();
            totalCreated++;
        }
        result.Reset();

        return result;
    }

    public static void Cleanup()
    {
        pool.Clear();
        totalCreated = 0;
    }
}

  核心逻辑就是获取对象和回收。回收时将对象push进栈,获取时,将栈里的pop出来,没有就创建。

  3、以buff为例的简单应用的例子

using System.Collections.Generic;
using UnityEngine;
public class ObjectPoolExamples: MonoBehaviour {

    private List<Buff> buffList = new List<Buff>();
    void Start () {
        ObjectPool<Buff>.maxCount = 20;
    }
    
    // Update is called once per frame
    void Update () {
        //点击右键添加buff
        if (Input.GetKeyDown(KeyCode.Mouse0))
        {
            Buff buff = ObjectPool<Buff>.GetObj();
            //随机给一些值
            buff.id = Random.Range(0, 100);
            buff.go = null;
            buff.endTime = Time.time + Random.Range(1f, 10f);
        }
        //时间到了回收buff
        for (int i = buffList.Count - 1; i >= 0; i--)
        {
            if (Time.time - buffList[i].endTime>0)
            {
                ObjectPool<Buff>.Recycle(buffList[i]);
                buffList.RemoveAt(i);
            }
        }
    }
}
public class Buff : IObject
{
    //buff的ID
    public int id;
    //buff的资源
    public GameObject go;
    //持续时间
    public float endTime;

    public void Reset()
    {
        Debug.Log("buff重置");
        id = 0;
        go = null;
        endTime = 0;
    }

    public void Cleanup()
    {
        Debug.Log("buff清理--并且抛出一条消息");
        id = 0;
        go = null;
        endTime = 0;
    }
}

  这个例子很简单,实际开发中逻辑复杂无数倍,但核心就是添加和移除buff,buff有明显的实效行,因此用对象池最合适。

  逻辑简单,代码也少,就不详细说明了。把代码挨个copy到工程里,随便一个实体挂上ObjectPoolExamples,就可以测试。

  

 

以上是关于Unity3D泛型对象池的主要内容,如果未能解决你的问题,请参考以下文章

Unity3D-对象池

Unity3D-对象池

Unity3D-对象池

Unity3D-对象池

Unity3d对象池

Unity3D 对象池思想 在游戏开发中的运用