UnityVR--Managers--对象池2

news2024/11/18 5:29:20

目录

前言

基本结构

对象池代码

对象池管理器代码 

使用

总结



前言

  经过上一篇对象池1的了解,已经做到了使用Unity自带的ObjectPool进行内存优化。本篇自己构建一个对象池管理器(Manager),实现对象池的创建、删除、加载资源等功能。这不是多此一举,因为在定义这个对象池管理器过程中,可以了解一个管理器Manager类的脚本,大致应该是如何的结构,之后还会写到很多的管理器Manager。

基本结构

    建立一个对象池的管理器(分配器),因为在场景中有可能同时存在多个对象池,需要一个管理器来管理从池中取出对象、回收对象等方法。也就是说,对象池管理器是一个工具集,包含了对象池操作的一般方法。

    对象池管理设计的总体结构如下图,有一个总的管理器(ChunkAllocator),它是一个管理器(Manager),因此是单例模式(即场上只有唯一一个实例);在ChunkAllocator建立一个字典(Dictionary<kew,value>)用来存储所有的对象池(Chunk),每个对象池(Chunk)都有一个列表List<T>,存储所有的对象。

 

     在管理器(ChunkAllocator)和对象池(Chunk)中,建立了以下场景中使用的工具方法:

  

对象池代码  Chunk.cs

   针对单个对象池的管理(想象上一篇中的Trophy对象池),需要实现的功能:1. 建立对象列表;2. 取一个对象;3. 消除一个对象;  

public class Chunk
{
    List<Object> objectList; //建立一个列表,作为对象池的容器
	public bool IsHave => objectList.Count > 0; //判断列表中有没有对象
    //当IsHave为True时才能使用GetObj()调取对象
  
	public Chunk()
	{//构造中先初始化容器(列表)
        objectList = new List<Object>();
	}

	public Object GetObj()
	{//从容器(列表)中取出对象
		Object obj = objectList[objectList.Count - 1]; //取出第一个对象
		objectList.RemoveAt(objectList.Count - 1);  //容器(列表)中移除这个被取出的对象
		return obj;
	}

	public void RevertObj(Object obj)
	{//回收对象到容器(列表)
		(obj as GameObject).transform.parent= null;  //将对象父节点设为空
        (obj as GameObject).SetActive(false);  //将对象失活
		objectList.Add(obj);  //最后添加回容器(列表)中
    }
}

对象池管理器代码 ChunkAllocator.cs

  管理器Manager代码继承单例(所有的管理类都是single)。对象池管理器实现的功能:1. 建立对象池字典;2. 判断对象池是否已经存在;3. 从对象池中获取一个对象并加载到场景内; 4. 通过资源管理器向对象池加入一个对象,并将它加载到场景内;5. 清空对象池

  *注:1. 这里使用的Resload(从Asset文件夹中加载资源)、Single(单例)等类,后面单开篇幅说明,这些是一个项目中的基本类;

  2. 方法还不够全面,仅测试参考。

//对象池分配器,单例
public class ChunkAllocator : Single<ChunkAllocator> 
{
    Dictionary<string, Chunk> chunkList; //定义一个字典存储所有的对象池

    public ChunkAllocator()
    {//构造中先实例化字典
        chunkList = new Dictionary<string, Chunk>();
    }

    private bool IsHavePool(string poolName)
    {//用对象池的名字查询是否已存在
        return chunkList.ContainsKey(poolName);
    }

    //获取对象
    public Object GetObject(string poolName)
    {//判断池子是否存在
        if (!IsHavePool(poolName))
        {
            return new Object();//不存在就直接实例化一个Object
        }
        return chunkList[poolName].GetObj(); //存在则通过名字找到它,并拿取对象
    }

    //回收对象到池中
    public void Revert(string poolName,Object obj)
    {
        if(IsHavePool(poolName))  //先判断对象池是否存在
        {
            chunkList[poolName].RevertObj(obj); //如果存在就直接回收进池
        }
        else
        {
            Chunk chunk= new Chunk(); //没有对应的对象池则先新建一个
            chunk.RevertObj(obj);     //再用新对象池回收该对象
            chunkList.Add(poolName, chunk);  //并把这个新对象池加入到字典中
        }
    }

    //直接从对象池中获取对象
    public GameObject GetGameObject(string poolName,GameObject gameObj,out bool isFirst,Transform parent=null)
    {//(对象池名称,对象,是否第一次创建,父节点)
        GameObject go = null;
        if(!IsHavePool(poolName))  //先判断对象池是否存在
        {//对象池不存在
            go = GameObject.Instantiate(gameObj); //实例化一个物体
            isFirst=true;  //将“第一次创建”的标记设为True
        }
        else
        {//对象池已存在
            isFirst = !chunkList[poolName].IsHave;  //池内有物体,就把“第一次创建”设false
            if (chunkList[poolName].IsHave)
            {
                go = chunkList[poolName].GetObj() as GameObject;//池内有物体就获取它
            }
            else
            {
                go = GameObject.Instantiate(gameObj); //池内没有物体就实例化一个
            }
        }
        if(parent != null)
        {//如果有父节点的要求,就将物体设置到父节点下
            go.transform.SetParent(parent);
        }
        go.transform.localScale = Vector3.one;  //设置物体大小
        go.transform.position = Vector3.zero;   //位置
        go.name= poolName;                      //名字
        go.SetActive(true);   //激活物体

        return go;  //返回物体
    }

    //从资源管理器中获取资源对象
    public T GetObj<T>(string poolName,string resName) where T : Object
    {
        if (!IsHavePool(poolName))
        {//如果对象池不存在,就用Resload加载Asset文件夹中的对象
            return Resload.Instance.LoadAsset<T>(resName);
        }
        return chunkList[poolName].GetObj() as T; //如果对象池存在,则直接调取对象
    }

    //从资源管理器中获取预制体
    public GameObject GetPrefab(string poolName,string resName,Transform parent=null)
    {
        GameObject go = null;
        if (!IsHavePool(poolName))
        {//如果对象池不存在,就用Resload加载
            go = Resload.Instance.LoadPrefab(resName);
        }
        else
        {//如果有对象池,先判断对象池中是否有东西
            if (chunkList[poolName].IsHave)
                go = chunkList[poolName].GetObj() as GameObject;//如果有,就从池中获取
            else
                go = Resload.Instance.LoadPrefab(resName);//否则就通过路径加载
        }
        if(parent!=null)
        {//设置父节点
            go.transform.SetParent(parent);
        }
        go.transform.localScale = Vector3.one;
        go.transform.position = Vector3.zero;
        go.SetActive(true);
        go.name = poolName;
        return go;
    }

    //清空对象池
    public void ClearPool(string poolName="")
    {
        if(poolName=="")
        {
            chunkList.Clear();
            return;
        }
        if(IsHavePool(poolName))
        {
            chunkList.Remove(poolName);  //如果对象池已存在,就清除
        }
    }
}

使用

    我们还是使用在上一篇的奖品(Trophy)中,场景结构不变,仅修改TrophyManager.cs

using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Pool;

public class TrophyManager : MonoBehaviour
{
    public GameObject[] trophies;
    public int number = 50;
    public bool useObjectPool;
    public bool useChunkAllocator;
    private ObjectPool<GameObject> trophyPool;

    void Start()
    {

    }

    void Update()
    {
        for (int i = 0; i < number; i++)
        {
            bool isfirst = false;
            GameObject trophy = ChunkAllocator.Instance.GetGameObject("trophyPool", trophies[Random.Range(0, trophies.Length)], out isfirst, transform);
            trophy.transform.localPosition = Random.insideUnitSphere;
            trophy.AddComponent<Trophy>();
            if (isfirst)
            {
                trophy.GetComponent<Trophy>().destroyEvent.AddListener(() =>
                {
                    ChunkAllocator.Instance.Revert("trophyPool", trophy);
                });
            }
        }

总结

  可以看出,管理器Manager是一个方法的集合,也就是把常用的一些方法放到一个类中。而且这个管理器的实现方式也有很多种,并根据不同的项目需要加入不同的工具方法,但是这个思路和结构是之后建立的项目通用的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/546348.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

机器视觉工程师很苦吗?年轻人不怕苦,就怕学不到东西,机器视觉销售>项目经理>视觉>电气>机械>老板

年轻人不怕苦&#xff0c;就怕学不到东西。 对于年轻人来说&#xff0c;需要规划&#xff0c;更需要发展。如果学不到东西&#xff0c;就会限制其发展&#xff0c;最重要的体现就是限制待遇上限。 一个非标自动化公司出差的频次&#xff08;各个公司略有差别&#xff0c;大多…

062:cesium设置泛光折线材质(material-6)

第062个 点击查看专栏目录 本示例的目的是介绍如何在vue+cesium中设置泛光折线材质,请参考源代码,了解PolylineGlowMaterialProperty的应用。 直接复制下面的 vue+cesium源代码,操作2分钟即可运行实现效果. 文章目录 示例效果配置方式示例源代码(共89行)相关API参考:专…

蓝桥:前端开发笔面必刷题——Day2 数组(三)

文章目录 &#x1f4cb;前言&#x1f3af;两数之和 II&#x1f4da;题目内容✅解答 &#x1f3af;移除元素&#x1f4da;题目内容✅解答 &#x1f3af;有序数组的平方&#x1f4da;题目内容✅解答 &#x1f3af;三数之和&#x1f4da;题目内容✅解答 &#x1f4dd;最后 &#x…

Cloud Studio 内核升级之持续优化

前言 Cloud Studio 是基于浏览器的集成式开发环境&#xff08;IDE&#xff09;&#xff0c;为开发者提供了一个永不间断的云端工作站。用户在使用 Cloud Studio 时无需安装&#xff0c;随时随地打开浏览器就能使用。云端开发体验与本地几乎一样&#xff0c;上手门槛更低&#…

Xcode 14.3 和 iOS 16.4 为 SwiftUI 带来了哪些新功能?

0. 概览 今年年初&#xff0c;Apple 推出了最新的 Xcode 14.3 以及对应的 iOS 16.4 。 与此同时&#xff0c;它们对目前最新的 SwiftUI 4.0 也添加了一些新功能&#xff1a; sheet 弹窗后部视图&#xff08;Interact with a view Behind a sheet&#xff09;可交互&#xff…

头歌计算机组成原理实验—运算器设计(7) 第7关:6位有符号补码阵列乘法器

第7关&#xff1a;6位有符号补码阵列乘法器 实验目的 帮助学生掌握补码阵列乘法器的实现原理。 视频讲解 实验内容 在 Logisim 中打开 alu.circ 文件&#xff0c;在6位补码阵列乘法器中利用5位阵列乘法器以及求补器等部件实现补码阵列乘法器&#xff0c;实验框架如图所示&a…

Linux - Shell 权限 权限管理 权限修改 权限身份的认证 目录的权限 粘滞位

shell命令以及运行原理 我们来输入指令的本质就是 输入字符串。 而指令的本质&#xff0c;就是编译好的文件和脚本&#xff0c;而只要是文件&#xff0c;就会在系统的特定路径下存放。 我们使用所有的指令最终都要在 OS &#xff08;操作系统&#xff09;内部运行&#xff0c;…

〖Python网络爬虫实战㉖〗- Selenium库和ChromeDriver驱动的安装

订阅&#xff1a;新手可以订阅我的其他专栏。免费阶段订阅量1000 python项目实战 Python编程基础教程系列&#xff08;零基础小白搬砖逆袭) 说明&#xff1a;本专栏持续更新中&#xff0c;目前专栏免费订阅&#xff0c;在转为付费专栏前订阅本专栏的&#xff0c;可以免费订阅付…

【C++】内存泄漏 智能指针

目录 一、什么是内存泄漏二、如何检测内存泄漏1、内存占用变化排查法2、valgrind定位法3、mtrace定位法 三、智能指针分类及作用1、unique_ptr2、shared_ptr3、weak_ptr 一、什么是内存泄漏 在实际的 C 开发中&#xff0c;我们经常会遇到诸如程序运行中突然崩溃、程序运行所用…

关于 HTTPS 的加密流程

目录 HTTP 与 HTTPS 的区别加密方式HTTPS 基本工作过程1. 仅使用对称密钥2. 引入非对称密钥对 key 进行加密3. 引入证书, 破解中间人攻击 HTTP 与 HTTPS 的区别 其实 HTTPS 与 HTTP 一样都是应用层协议, HTTPS 只是在 HTTP 的基础上再加上了一个加密层. 为啥要对 HTTP 进行加密…

bugku---misc

一.telnet 下载后是一个压缩包 条件反射&#xff0c;先丢在wireshark中看一下&#xff0c; 直接搜flag&#xff0c;就 出来了 Data: flag{d316759c281bf925d600be698a4973d5} 二.简单取证1 之前只做过取证大赛的&#xff0c;但是这个没有啥思路&#xff0c;看了一下需要工具m…

Redis集群简介及槽位映射(哈希取余和一致性哈希算法)

redis cluster需求至少需要3个master才能组成一个集群&#xff0c;同时每个sentinel至少有一个slave节点&#xff0c;各个节点之间保持tcp通信。当master发生宕机&#xff0c;redis cluster自动将对应的slave节点提拔为master,来重新对外提供服务。 先来说一下槽&#xff0c;集…

从“被动发现”变为“主动感知”|智能井盖脚下安全守护者

井盖作为城市基础设施的重要组成部分&#xff0c;具有关键的作用。城市的管道网络错综复杂&#xff0c;包括雨水、污水、弱电和强电等。其中&#xff0c;雨水和污水管道的管径较大&#xff0c;可能会导致隐藏或其他安全事故的发生。而弱电井则是整个城市信息传输的重要环节&…

Java 基础进阶篇(十四):File 类常用方法

File 类的对象代表操作系统的文件&#xff08;文件、文件夹&#xff09;&#xff0c;File 类在 java.io.File 包下。 File 类提供了诸如&#xff1a;创建文件对象代表文件&#xff0c;获取文件信息&#xff08;大小、修改时间&#xff09;、删除文件、创建文件&#xff08;文件…

Java【文件和IO】File 类, 字节IO流的使用

文章目录 前言一、File 类1, 构造方法2, 成员方法 二、字节流输入输出1, 字节流输入 InputStream1.1, 每次输入一个字节1.2, 每次输入多个字节 2, 字节流输出 OutputStream2.1, 每次输出一个字节2.2, 每次输出多个字节 总结 前言 各位读者好, 我是小陈, 这是我的个人主页, 希望…

chatgpt赋能Python-python3__2怎么算

Python3中<<2的计算方法 Python3是一种高级编程语言&#xff0c;它具有强大的数据分析和计算能力。在Python3中&#xff0c;<<2是一种用于移位计算的运算符。在本篇文章中&#xff0c;我们将介绍Python3中<<2的计算方法。 什么是移位运算符 移位运算符是一…

C++基础语法——内存管理

1. C/C中的内存管理 我们先看如下一段代码 #include <iostream>using namespace std;int globalVar 1; static int staticGlobalVar 1;void Test() {static int staticVar 1;int localVar 1;int num1[10] { 1, 2, 3, 4 };char char2[] "abcd";const ch…

rk3399 buildroot ubuntu20版本编译遇到问题

一、编译uboot遇到问题 /usr/include/libfdt.h:258:1: error: redefinition of fdt_set_version 258 | fdt_set_hdr_(version); | ^~~~~~~~~~~~ In file included from tools/fdt_host.h:11, from tools/imagetool.h:22, from tools…

BurpSuite—-Target模块(目标模块)

前言 本文主要介绍BurpSuite—-Target模块(目标模块)的相关内容 关于BurpSuite的安装可以看一下之前这篇文章&#xff1a; http://t.csdn.cn/cavWt Target功能 目标工具包含了SiteMap&#xff0c;用你的目标应用程序的详细信息。它可以让你定义哪些对象在范围上为你目前的工…

基于QGIS的长株潭城市群边界范围融合实战

背景 在面向区域的研究过程中&#xff0c;比如一些研究区域&#xff0c;如果是具体的行政区划&#xff0c;比如具体的某省或者某市或者县&#xff0c;可以直接从国家官方的地理数据中直接下载就可以。但如果并没有直接的空间数据那怎么办呢&#xff1f;比如之前遇到的一个场景&…