zoukankan      html  css  js  c++  java
  • 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,就可以测试。

      

  • 相关阅读:
    经典SQL语句大全
    C# 在子线程中创建不会阻塞执行窗体
    win7 C# winForm编程 savefiledialog 不能弹出保存窗体
    什么是AJAX技术及其常识
    C++安装失败解决办法
    java实现图像的直方图均衡以及灰度线性变化,灰度拉伸
    java关于邮件发送
    我都博客第一天
    开博随笔
    git使用
  • 原文地址:https://www.cnblogs.com/lihangppz/p/9356877.html
Copyright © 2011-2022 走看看