当前位置: 首页 > news >正文

高效对象池设计:提升Unity性能的关键

缓冲池(对象池)模块

缓存池(对象池)的主要作用是优化资源管理,提高程序性能。主要通过重复利用已经创建的对象,避免频繁的创建和销毁过程,从而减少系统的内存分配和垃圾回收带来的开销。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;/// <summary>
/// 缓存池(对象池)模块 管理器
/// </summary>
public class PoolMgr : BaseManager<PoolMgr>
{//声明柜子(Dictionary)和抽屉(List)容器private Dictionary<string,List<GameObject>> poolDic = new Dictionary<string,List<GameObject>>();private PoolMgr() { }/// <summary>/// 拿东西的方法/// </summary>/// <param name="name"> 抽屉容器的名字 </param>/// <returns></returns>public GameObject GetObjFromPool(string name){GameObject obj;//有抽屉 并且 抽屉中有对象if (poolDic.ContainsKey(name) && poolDic[name].Count > 0){//直接返回第一个对象obj = poolDic[name][0];poolDic[name].RemoveAt(0);obj.SetActive(true);}//否则应该创建else{//没有的话 通过资源加载 实例化一个对象并返回obj = GameObject.Instantiate(Resources.Load<GameObject>(name));obj.name = name;}return obj;}/// <summary>/// 往缓存池放入对象/// </summary>/// <param name="obj">希望放入的对象</param>public void PushObjToPool(GameObject obj){//并不是直接移除对象,而是将对象失活  再用时再激活obj.SetActive(false);//如果存在对应的抽屉容器 可以直接放if (poolDic.ContainsKey(obj.name)){poolDic[obj.name].Add(obj);}//如果没有对应的容器可以先创建再放else{poolDic.Add(obj.name, new List<GameObject>());poolDic[obj.name].Add(obj);}}/// <summary>/// 用于清除整个柜子当中的数据/// 使用场景主要好是 切换场景/// </summary>public void ClearPool(){ poolDic.Clear();}
}
窗口布局优化

现在直接关活对象,当之后项目做大了,抽屉多了,对象多了,游戏中成百上千个对象,在开发测试时不方便从Hierarchy窗口中查看对象获取信息,因此我们希望能优化一下Hierarchy窗口中的布局,将对象和抽屉的关系可视化

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 抽屉(池子中的数据)对象
/// </summary>
public class PoolData
{ //用来存储抽屉中的对象private List<GameObject> dataList = new List<GameObject>();//抽屉跟对象,用来布局private GameObject rootObj;//获取容器中对象的数量public int Count => dataList.Count;public PoolData(GameObject root,string name) {if (PoolMgr.isOpenLayout){//创建抽屉父对象rootObj = new GameObject(name);//将抽屉父对象与柜子父对象设置为父子关系rootObj.transform.SetParent(root.transform);}}/// <summary>/// 取出抽屉中的对象/// </summary>/// <returns></returns>public GameObject GetGameObject(){//取出对象GameObject obj = dataList[0];dataList.RemoveAt(0);//激活对象obj.SetActive(true);//取出去的时候断开父子关系if (PoolMgr.isOpenLayout)obj.transform.SetParent(null);return obj;}/// <summary>/// 将对象放入抽屉中/// </summary>/// <param name="obj"></param>public void Push(GameObject obj){//失活对象obj.SetActive(false);//设置父子关系if (PoolMgr.isOpenLayout)obj.transform.SetParent(rootObj.transform);//添加进listdataList.Add(obj);}
}/// <summary>
/// 缓存池(对象池)模块 管理器
/// </summary>
public class PoolMgr : BaseManager<PoolMgr>
{//声明柜子(Dictionary)和抽屉(List)容器private Dictionary<string, PoolData> poolDic = new Dictionary<string, PoolData>();//池子根对象private GameObject poolObj;//是否开启布局功能public static bool isOpenLayout = true;private PoolMgr() { }/// <summary>/// 拿东西的方法/// </summary>/// <param name="name"> 抽屉容器的名字 </param>/// <returns></returns>public GameObject GetObjFromPool(string name){GameObject obj;//有抽屉 并且 抽屉中有对象if (poolDic.ContainsKey(name) && poolDic[name].Count > 0){//取出抽屉中的对象obj = poolDic[name].GetGameObject();}//否则应该创建else{//没有的话 通过资源加载 实例化一个对象并返回obj = GameObject.Instantiate(Resources.Load<GameObject>(name));obj.name = name;}return obj;}/// <summary>/// 往缓存池放入对象/// </summary>/// <param name="obj">希望放入的对象</param>public void PushObjToPool(GameObject obj){//如果根对象为空才创建if (poolObj == null && isOpenLayout)poolObj = new GameObject("Pool");//并不是直接移除对象,而是将对象失活  再用时再激活obj.SetActive(false);//失活之后设置父对象if(isOpenLayout)obj.transform.SetParent(poolObj.transform);//如果没有对应的容器可以先创建再放if (!poolDic.ContainsKey(obj.name))poolDic.Add(obj.name, new PoolData(poolObj, obj.name));poolDic[obj.name].Push(obj);}/// <summary>/// 用于清除整个柜子当中的数据/// 使用场景主要好是 切换场景/// </summary>public void ClearPool(){ poolDic.Clear();poolObj = null;}
}
对象上限优化

目前我们制作的缓存池模块

理论上来说,当动态创建的对象长时间不放回抽屉

每次从缓存池中动态获取对象时,会不停的新建对象

那么也就是对象的数量是没有上限的

场景上的某种对象可以存在n个

而对象上限优化指的就是

我们希望控制对象数量有上限

对于不重要的资源我们没必要让其无限加量

而是将“使用最久”的资源直接抢来用

主要目的:

更加彻底的复用资源 ,对对象的数量上限加以限制 ,可以优化内存空间,甚至优化性能(减少数量上限,可以减小渲染压力)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 抽屉(池子中的数据)对象
/// </summary>
public class PoolData
{ //用来存储抽屉中的对象 记录的是没有使用的对象private List<GameObject> dataList = new List<GameObject>();//抽屉跟对象,用来布局private GameObject rootObj;//抽屉上限,场景上同时存在的对象的上限个数private int maxNum;//记录使用中的对象private List<GameObject> usedList = new List<GameObject>();//获取容器中对象的数量public int Count => dataList.Count;public int UsedCount => usedList.Count;public bool NeedCreate => usedList.Count < maxNum;public PoolData(GameObject root,string name, GameObject usedObj) {if (PoolMgr.isOpenLayout){//创建抽屉父对象rootObj = new GameObject(name);//将抽屉父对象与柜子父对象设置为父子关系rootObj.transform.SetParent(root.transform);}//创建抽屉时 外部会动态创建一个对象//我们需要将它记录在使用中的容器中usedList.Add(usedObj);//DelayRemove 挂载在需要对象池创建的对象身上的脚本//主要定义了maxNum,对象在对象池中的上限以及延迟调用PushObjToPool函数让对象失活DelayRemove delayRemove = usedObj.GetComponent<DelayRemove>();if (delayRemove == null){Debug.LogError("请为使用对象池的预设体挂载DelayRemove脚本");return;}maxNum = delayRemove.maxNum;}/// <summary>/// 取出抽屉中的对象/// </summary>/// <returns></returns>public GameObject GetGameObject(){//取出对象GameObject obj;if (Count > 0)  //如果抽屉中有未使用的话直接使用{obj = dataList[0];dataList.RemoveAt(0);usedList.Add(obj);}else //抽屉中没有未使用的{//取使用中的List抽屉中的第一个,代表使用时间最长的obj = usedList[0];//并把它从list中移除掉usedList.RemoveAt(0);//由于还要使用,再把它记录到List的最后一个usedList.Add(obj);}//激活对象obj.SetActive(true);//取出去的时候断开父子关系if (PoolMgr.isOpenLayout)obj.transform.SetParent(null);return obj;}/// <summary>/// 将对象放入抽屉中/// </summary>/// <param name="obj"></param>public void Push(GameObject obj){//失活对象obj.SetActive(false);//设置父子关系if (PoolMgr.isOpenLayout)obj.transform.SetParent(rootObj.transform);//添加进listdataList.Add(obj);//这个对象已经不再使用 需要从使用中容器中移除usedList.Remove(obj);}/// <summary>/// 往使用中的容器添加对象/// </summary>/// <param name="obj"></param>public void PushUsedList(GameObject obj){//添加进listusedList.Add(obj);}
}/// <summary>
/// 缓存池(对象池)模块 管理器
/// </summary>
public class PoolMgr : BaseManager<PoolMgr>
{//声明柜子(Dictionary)和抽屉(List)容器private Dictionary<string, PoolData> poolDic = new Dictionary<string, PoolData>();//池子根对象private GameObject poolObj;//是否开启布局功能public static bool isOpenLayout = true;private PoolMgr() { }/// <summary>/// 拿东西的方法/// </summary>/// <param name="name"> 抽屉容器的名字 </param>/// <returns></returns>public GameObject GetObjFromPool(string name){if (poolObj == null && isOpenLayout)poolObj = new GameObject("Pool");GameObject obj;#region 没有加入上限时的逻辑////有抽屉 并且 抽屉中有对象//if (poolDic.ContainsKey(name) && poolDic[name].Count > 0)//{//    //取出抽屉中的对象//    obj = poolDic[name].GetGameObject();//}////否则应该创建//else//{//    //没有的话 通过资源加载 实例化一个对象并返回//    obj = GameObject.Instantiate(Resources.Load<GameObject>(name));//    obj.name = name;//}#endregionif (!poolDic.ContainsKey(name) ||(poolDic[name].Count == 0 && poolDic[name].NeedCreate)){//没有的话 通过资源加载 实例化一个对象并返回obj = GameObject.Instantiate(Resources.Load<GameObject>(name));obj.name = name;if (!poolDic.ContainsKey(name))//创建抽屉poolDic.Add(name, new PoolData(poolObj, name, obj));elsepoolDic[name].PushUsedList(obj);//实例化出来的对象需要添加到使用中的List}//当抽屉中有对象 或者 使用中的对象超上限的情况下else{obj = poolDic[name].GetGameObject();}return obj;}/// <summary>/// 往缓存池放入对象/// </summary>/// <param name="obj">希望放入的对象</param>public void PushObjToPool(GameObject obj){//如果根对象为空才创建if (poolObj == null && isOpenLayout)poolObj = new GameObject("Pool");//并不是直接移除对象,而是将对象失活  再用时再激活obj.SetActive(false);//失活之后设置父对象if(isOpenLayout)obj.transform.SetParent(poolObj.transform);//如果没有对应的容器可以先创建再放poolDic[obj.name].Push(obj);}/// <summary>/// 用于清除整个柜子当中的数据/// 使用场景主要好是 切换场景/// </summary>public void ClearPool(){ poolDic.Clear();poolObj = null;}
}
http://www.dtcms.com/a/536838.html

相关文章:

  • 网站建设需要了解哪些信息常州网站制作公司
  • 如何做正版小说网站工厂电商具体是做什么的
  • 磁盘和注册表清理工具
  • 【windows】证书引起的浏览器请求问题-https红色斜线-解决方法
  • mormot2创建一个httpserver
  • 科技类网站简介怎么做有哪些游戏可以做网站
  • 定制化TTS数据实践:解锁语音大模型的无限潜能
  • 微网站是什么嘉兴高端网站定制
  • 一分钟讲透:c++新特性string_view
  • sns社交网站 建设做网站图片尺寸
  • 营销网站结构网站免费优化平台
  • 免费视频模板网站制作微信网页
  • android实践:loadUrl执行JavaScript异常
  • FFmpeg 基本数据结构 AVCodecParser分析
  • celery知识点总结
  • langchain将用户问题转sql查询探索
  • compareAndSet怎么用
  • Skill Seeker——一站式自动化将文档网站、GitHub 仓库和 PDF 文件转换为可部署 AI 技能的深度解析
  • 浅谈 Agent 开发工具链演进历程
  • 帝国cms小说阅读网站模板果洛电子商务网站建设哪家快
  • 学校网站建设背景科技作品手工
  • SmartPLS下载安装教程(附安装包)SmartPLS 4.1保姆级图文教程
  • ECR扫描管理功能完整实现:提升云原生镜像安全管控效率
  • PySide6 Win10记事本从零到一——第二章 第一个窗口程序
  • 商务英语资源合集
  • Shell 变量
  • 基于vue的在线学习系统
  • 【题解】洛谷 P4291 [HAOI2008] 排名系统 [字符串 + 平衡树]
  • html5做网站好吗漳州做网站制作
  • 做网站从哪里找货源江门制作公司网站