zoukankan      html  css  js  c++  java
  • unity中实现简单对象池,附教程原理

    Unity对象池的创建与使用


    本文提供全流程,中文翻译。

    Chinar 坚持将简单的生活方式,带给世人!

    (拥有更好的阅读体验 —— 高分辨率用户请根据需求调整网页缩放比例)



    Chinar —— 心分享、心创新!

    助力快速完成 Unity 对象池的创建与使用

    为新手节省宝贵的时间,避免采坑!


    Chinar 教程效果:



    全文高清图片,点击即可放大观看 (很多人竟然不知道)


    1

    MonoSingleton —— 单例基类


    任何继承自 MonoSingleton 泛型基类的脚本/类 都是单例类

    举个栗子黑白88

    using UnityEngine;
    
    
    /// <summary>
    /// 泛型单例基类 —— 任何继承自该类的类,都是单例类
    /// </summary>
    /// <typeparam name="T">泛型</typeparam>
    public abstract class MonoSingleton<T> : MonoBehaviour where T : MonoSingleton<T>
    {
        private static T instance;
        public static T Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = FindObjectOfType(typeof(T)) as T;
                    if (instance == null) instance = new GameObject("Chinar Single of " + typeof(T).ToString(), typeof(T)).GetComponent<T>();
                }
    
                return instance;
            }
        }
    
    
        private void Awake()
        {
            if (instance == null) instance = this as T;
        }
    
    
        private void OnApplicationQuit()
        {
            instance = null;
        }
    }

    2

    ObjectPool —— 对象池


    新建一个脚本 ObjectPool 继承自泛型基类 MonoSingleton《ObjectPool》

    是以 ObjectPool 就会是一个单例类
    举个栗子黑白88

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    
    /// <summary>
    /// 对象池(重复调用/使用的游戏物体)  子弹,技能,导弹,敌人
    /// </summary>
    public class ObjectPool : MonoSingleton<ObjectPool>
    {
        //字段  池 技能预设物(因为一个技能可能有多个预制件) 技能的复用性
        private Dictionary<string, List<GameObject>> cache = new Dictionary<string, List<GameObject>>();
        int                                          i     = 0; //标记 0
    
    
        /// <summary>
        /// 创建显示对象
        /// </summary>
        /// <returns>The object.</returns>
        /// <param name="key">对象名称</param>
        /// <param name="go">对象的预制件</param>
        /// <param name="position">对象的新位置</param>
        /// <param name="quaternion">对象的角度</param>
        public GameObject CreateObject(string key, GameObject go, Vector3 position, Quaternion quaternion)
        {
            GameObject tempgo = cache.ContainsKey(key) ? cache[key].Find(p => !p.activeSelf) : null; //返回池中未激活的对象,所有都被激活就返回空,赋值给临时对象
            if (tempgo != null)                                                                      //如果临时对象不为空
            {
                tempgo.transform.position = position;   //设置位置
                tempgo.transform.rotation = quaternion; //旋转信息
            }
            else //否则,就是空了。(也就是没能从池子里取出对象)
            {
                tempgo = Instantiate(go, position, quaternion); //那就根据传入的预设物,生成一个新物体
                print("实例化物体数量:" + i++);
                if (!cache.ContainsKey(key)) //池中没有键
                {
                    cache.Add(key, new List<GameObject>()); //新建一个 列表
                }
    
                cache[key].Add(tempgo); //给字典中的列表加入/add 临时物体,如果有键就直接添加了
            }
    
            tempgo.SetActive(true); //并启用临时物体
            return tempgo;          //返回
        }
    
    
        /// <summary>
        /// 直接回收
        /// </summary>
        /// <param name="go">Go.</param>
        public void CollectObject(GameObject go)
        {
            go.SetActive(false);
        }
    
    
        /// <summary>
        /// 延迟回收
        /// </summary>
        /// <param name="go">Go.</param>
        /// <param name="delay">Delay.</param>
        public void CollectObject(GameObject go, float delay)
        {
            StartCoroutine(Collect(go, delay));
        }
    
    
        private IEnumerator Collect(GameObject go, float delay)
        {
            yield return new WaitForSeconds(delay);
            CollectObject(go);
        }
    
    
        /// <summary>
        /// 释放资源
        /// </summary>
        /// <returns>The clear.</returns>
        /// <param name="key">Key.</param>
        public void Clear(string key)
        {
            if (cache.ContainsKey(key))
            {
                //Destroy当中所有的对象
                for (int i = 0; i < cache[key].Count; i++)
                {
                    Destroy(cache[key][i]);
                }
    
                //清除键当中的所有值
                //cache[key].Clear();
                //清除这个键(键值一起清除)
                cache.Remove(key);
            }
        }
    
    
        /// <summary>
        /// 释放所有对象池
        /// </summary>
        public void ClearAll()
        {
            var list = new List<string>(cache.Keys);
            for (int i = 0; i < list.Count; i++)
            {
                Clear(list[i]);
            }
        }
    }

    3

    PoolTest —— 测试对象池的使用


    新建一个脚本 PoolTest 用来测试对象池的使用
    举个栗子黑白88

    using UnityEngine;
    
    
    /// <summary>
    /// 测试对象池的调用
    /// </summary>
    public class PoolTest : MonoBehaviour
    {
        GameObject go;   //临时对象
        GameObject item; //临时对象池对象
    
    
        void Start()
        {
            go = Resources.Load<GameObject>("Cube"); //在Resources文件目录下做一个Cube预设物
        }
    
    
        void Update()
        {
            if (Input.GetKey(KeyCode.Space)) //按下空格创建一个Cube
            {
                item                    =  ObjectPool.Instance.CreateObject("Object1", go, Vector3.zero, new Quaternion(0, 0, 0, 0));
                item.transform.position += new Vector3(0, 0, 1);
            }
    
    
            if (Input.GetMouseButtonDown(0)) //按下左键执行回收对象
            {
                if (item != null)
                {
                    ObjectPool.Instance.CollectObject(item, 0.2f);
                }
            }
    
    
            if (Input.GetMouseButtonDown(1)) //按下右键执行清除已经生成的对象
            {
                ObjectPool.Instance.Clear("Object1");
            }
        }
    }

    支持

    May Be —— 搞开发,总有一天要做的事!


    拥有自己的服务器,无需再找攻略!

    Chinar 提供一站式教程,闭眼式创建!

    为新手节省宝贵时间,避免采坑!


    先点击领取 —— 阿里全产品优惠券 (享受最低优惠)


    1 —— 云服务器超全购买流程 (新手必备!)

    2 —— 阿里ECS云服务器自定义配置 - 购买教程(新手必备!)

    3—— Windows 服务器配置、运行、建站一条龙 !

    4 —— Linux 服务器配置、运行、建站一条龙 !





    Chinar


    END

    本博客为非营利性个人原创,除部分有明确署名的作品外,所刊登的所有作品的著作权均为本人所拥有,本人保留所有法定权利。违者必究

    对于需要复制、转载、链接和传播博客文章或内容的,请及时和本博主进行联系,留言,Email: ichinar@icloud.com

    对于经本博主明确授权和许可使用文章及内容的,使用时请注明文章或内容出处并注明网址

  • 相关阅读:
    代码发布一
    Qt之QThread(深入理解)
    Azure 云助手正式发布
    Qt之自定义控件(开关按钮)
    CentOS 7.x安装配置
    CSDN中的Bug
    Qt之findChild
    CentOS 6.x启动时网卡eth0未激活
    CentOS 6.x安装配置
    CentOS所有下载
  • 原文地址:https://www.cnblogs.com/chinarbolg/p/9601390.html
Copyright © 2011-2022 走看看