zoukankan      html  css  js  c++  java
  • 《Unity3D》通过对象池模式,管理场景中的元素

    池管理类有啥用?

    在游戏场景中,我们有时候会需要复用一些游戏物体,比如常见的子弹、子弹碰撞类,某些情况下,怪物也可以使用池管理,UI部分比如:血条、文字等等

    这些元素共同的特性是:存在固定生命周期,使用比较频繁,场景中大量使用。

    所以,我们就通过池管理思路,在游戏初始化的时候,生成一个初始的池,存放我们要复用的元素,

    当要用到时,从池中取出;生命周期结束,放回到池中。

    代码

    这个池的参数有两个:1池中存放的元素 2 池的初始容量(如果池不够了,则会按照这个容量进行扩展)

    代码如下

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    /// <summary>
    /// 通用的池管理类
    /// </summary>
    public class ObjectPoolManager : MonoBehaviour
    {
        #region 公共属性
    
        /// <summary>
        /// 池中所使用的元素Prefab
        /// </summary>
        public GameObject ObjPrefab;
    
        /// <summary>
        /// 初始容量
        /// </summary>
        public int InitialCapacity;
    
        #endregion
    
        #region 私有属性
    
        /// <summary>
        /// 初始下标
        /// </summary>
        private int _startCapacityIndex;
    
        /// <summary>
        /// 可用下标
        /// </summary>
        private List<int> _avaliableIndex;
    
        /// <summary>
        /// 池中全部元素
        /// </summary>
        private Dictionary<int, GameObject> _totalObjList;
    
        #endregion
    
        #region 事件/重写方法
    
        void Start()
        {
            _avaliableIndex = new List<int>(InitialCapacity);
            _totalObjList = new Dictionary<int, GameObject>(InitialCapacity);
            expandPool();
        }
        #endregion
    
        #region 公共方法
    
        /// <summary>
        /// 取得一个物体,返回值 1,obj代表,ID是1的物体被取到,ID可以用来归还物体的时候用到
        /// </summary>
        /// <returns></returns>
        public KeyValuePair<int, GameObject> PickObj()
        {
    
            if (_avaliableIndex.Count == 0)
                expandPool();
    
            int id = _avaliableIndex[0];
            _avaliableIndex.Remove(id);
    
            _totalObjList[id].SetActive(true);
            return new KeyValuePair<int, GameObject>(id, _totalObjList[id]);
        }
    
        /// <summary>
        /// 从池中取出元素,在制定时间后回收
        /// </summary>
        /// <param name="existSecond"></param>
        /// <returns></returns>
        public KeyValuePair<int, GameObject> PickObjWithDelayRecyle(float existSecond)
        {
            KeyValuePair<int, GameObject> obj = PickObj();
            StartCoroutine(startRecycleExplosion(obj.Key, existSecond));
            return obj;
        }
    
    
        /// <summary>
        /// 回收一个物体
        /// </summary>
        /// <param name="id"></param>
        public void RecyleObj(int id)
        {
            _totalObjList[id].SetActive(false);
            _totalObjList[id].transform.parent = transform;
            _avaliableIndex.Add(id);
        }
    
        #endregion
    
        #region 私有方法
    
        IEnumerator startRecycleExplosion(int id, float waitTime)
        {
            yield return new WaitForSeconds(waitTime);
            RecyleObj(id);
        }
    
        /// <summary>
        /// 扩展池
        /// </summary>
        private void expandPool()
        {
            int start = _startCapacityIndex;
            int end = _startCapacityIndex + InitialCapacity;
    
            for (int i = start; i < end; i++)
            {
                //加入验证判断,避免在多个请求同时触发扩展池需求
                if (_totalObjList.ContainsKey(i))
                    continue;
    
                GameObject newObj = Instantiate(ObjPrefab) as GameObject;
                newObj.SetActive(false);
                _avaliableIndex.Add(i);
                _totalObjList.Add(i, newObj);
            }
            _startCapacityIndex = end;
        }
        #endregion
    }

    值得注意的是:放回池中的时候,我们把元素的父节点也设置为池元素,这样做是避免当元素挂载的对象在内存中被删除的时候,元素也被删除的问题。

    调用

     将本类挂载到场景中的某个GameObject上,在U3D编辑界面进行参数的赋值,就可以再游戏中访问了。

    声明方式:

     ObjectPoolManager _bulletPool = GameObject.Find("你挂载的物体名称").GetComponent<ObjectPoolManager>();

    取出元素:

      KeyValuePair<int, GameObject> bulletKV = _bulletPool.PickObj();

    放回:

     _bulletPool.RecyleObj(bulletID);

    在本人的实际使用中,用这个类管理了

    1. 子弹
    2. 子弹碰撞特效
    3. 攻击特效
    4. 被攻击特效
    5. 怪物血条(基于NGUI制作)
    6. 场景部分文字(施法时、怪物被攻击时,基于NGUI制作)
    7. 等等。。

    欢迎各位进行讨论

  • 相关阅读:
    Azure School女神相邀,把每分钟都过的更充实
    Java、Node.js、PHP还是.Net? 无论你选谁,我都能教你一招!
    一样的Java,不一样的HDInsight大数据开发体验
    第五代微软小冰 | 你有一个来自人工智能的电话待接听
    2017“编程之美”终章:AI之战勇者为王
    大数据freestyle: 共享单车轨迹数据助力城市合理规划自行车道
    语音识别技术里程碑:错误率降至5.1%,超过专业速记员
    wait和waitpid
    Linux网络编程wait()和waitpid()的讲解
    如何测试Linux 中的wait函数能不能等待子进程的子进程?
  • 原文地址:https://www.cnblogs.com/kimmy/p/3808007.html
Copyright © 2011-2022 走看看