Unity框架学习--对象池

       频繁创建和销毁对象会造成性能的开销。
        创建对象的时候,系统会为这个对象开辟一片新的空间。销毁对象的时候,这个对象会变成内存垃圾,当内存垃圾达到一定程度,就会触发垃圾回收机制,清理内存垃圾,由于此时在清理垃圾,所以程序有可能就会变卡。

        为了改善这个问题,我们就可以使用对象池。使用了它之后,程序的性能就能得到提升不那么容易变卡。

        对象池的原理:


        1、当要创建对象的时候,不直接创建,而是先从对象池里面找,如果对象池里有这种类型的对象,就从对象池中取出来用。如果对象池里面没有这种类型的对象,才创建该对象。
        2、当要销毁对象的时候,不直接销毁,而是把这个对象放进对象池里面存着,以便下一次创建对象时使用。

一个预制体对应一个对象池,代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;/// <summary>
/// 对象池
/// </summary>
public class ObjectPool : MonoBehaviour
{public GameObject prefabs;   //这个对象池存储的游戏对象的预制体public int capcity = 100;  //对象池的容量//从这个对象池中取出来正在使用的游戏对象public List<GameObject> usedGameObjectList = new List<GameObject>();//存在这个对象池中没有被使用的游戏对象public List<GameObject> unusedGameObjectList = new List<GameObject>();//这个池子总共拥有的游戏对象的个数public int TotalGameObjectCount { get => usedGameObjectList.Count + unusedGameObjectList.Count; }/// <summary>/// 从对象池中获取一个对象,并返回一个对象/// </summary>public GameObject Spawn(Vector3 position,Quaternion rotation,Transform parent=null){GameObject go;//池子中有if (unusedGameObjectList.Count > 0){go = unusedGameObjectList[0];unusedGameObjectList.RemoveAt(0);usedGameObjectList.Add(go);go.transform.localPosition = position;go.transform.localRotation = rotation;go.transform.SetParent(parent, false);go.SetActive(true);}else  //对象池中没有,实例化{go = Instantiate(prefabs, position, rotation, parent);usedGameObjectList.Add(go);}//如果该游戏对象身上继承MonoBehaviour的脚本中写了名叫OnSpwan的方法,则会执行它们一次//                                           就算没有接收者也不报错go.SendMessage("OnSpawn", SendMessageOptions.DontRequireReceiver);return go;}//回收进对象池中public void DesPawn(GameObject go){if (go == null) return;//遍历这个对象池中所有正在使用的游戏对象for (int i = 0; i < usedGameObjectList.Count; i++){if (usedGameObjectList[i] == go){//如果这个对象池的容量不为负数,且容纳的游戏对象已经满了,则把0号游戏对象删除掉//确保之后新的游戏对象能放入池子中if (capcity >= 0 && usedGameObjectList.Count >= capcity){if (unusedGameObjectList.Count>0){DesPawn(unusedGameObjectList[0]);unusedGameObjectList.RemoveAt(0);}}//把游戏对象回收到对象池中unusedGameObjectList.Add(go);usedGameObjectList.RemoveAt(i);//如果该游戏对象身上继承MonoBehaviour的脚本写了名叫OnDespawn的方法,则在回收的时候会执行一次//这个方法用来在回收前将游戏对象还原go.SendMessage("OnDespawn", SendMessageOptions.DontRequireReceiver);go.SetActive(false);go.transform.SetParent(transform, false);  //取消子物体return;}}}/// <summary>/// 把通过这个对象池生成的所有对象全部隐藏并放入对象池中/// </summary>public void DesPawnAll(){int count = usedGameObjectList.Count;for (int i = 1; i <= count; i++){DesPawn(usedGameObjectList[0]);}usedGameObjectList.Clear();}/// <summary>/// 预加载的方法,预先在池子里放几个对象/// </summary>public void PreLoad(int amount = 1){if (prefabs == null) return;if (amount <= 0) return;for (int i = 1; i <= amount ; i++){GameObject go = Instantiate(prefabs, Vector3.zero, Quaternion.identity);go.SetActive(false);go.transform.SetParent(transform, false);unusedGameObjectList.Add(go);go.name = prefabs.name;  //更改一下生成的物体的名字}}}

一个预制体一个池子,然后一个大的池子管理所有的小对象池

using System.Collections;
using System.Collections.Generic;
using UnityEngine;/// <summary>
/// 对象池管理,可以通过这个管理器从对象池生成游戏对象,也可以回收游戏对象进对象池
/// </summary>
public class ObjectPoolsManager : SingletonPatternBase<ObjectPoolsManager>
{GameObject poolsParent;  //所有对象池的父物体string poolsParentName = "ObjectPools";  //大对象池的名字//当前所有小对象池的列表public List<ObjectPool> objectPoolsList = new List<ObjectPool>();public Dictionary<GameObject, ObjectPool> objectDictionary = new Dictionary<GameObject, ObjectPool>();/// <summary>/// 从对象池生成游戏对象/// 如果对象池有,从对象池中取出来用/// 如果对象池没有,实例化该对象/// </summary>public GameObject Spawn(GameObject prefab,Vector3 position,Quaternion rotation,Transform parent=null){if (prefab == null) return null;//如果场景中没有对象池的父物体,则生成一个空物体作为所有对象池的父物体CreatePoolsParentIfNull();//先通过预制体查找它所属的小对象池,如果找到了,则返回这个小对象池//如果找不到,则创建一个小对象池,用来存放这种预制体ObjectPool objectPool = FindPoolByPrefabOrCreatePool(prefab);GameObject go = objectPool.Spawn(position, rotation, parent);objectDictionary.Add(go, objectPool);return go;}/// <summary>/// 回收的方法/// </summary>public void DesPawn(GameObject go,float delayTime=0){if (go == null) return;MonoManager.Instance.StartCoroutine(DespawnCoroutine(go, delayTime));}IEnumerator DespawnCoroutine(GameObject go, float delayTime = 0){//等待指定的秒数yield return new WaitForSeconds(delayTime);if (objectDictionary.TryGetValue(go, out ObjectPool pool)){objectDictionary.Remove(go);pool.DesPawn(go);}else{//获取这个游戏对象所属的对象池pool = FindPoolByUsedGameObject(go);if (pool != null){pool.DesPawn(go);}}}/// <summary>/// 通过正在使用的物体获取这个游戏对象所属的对象池/// </summary>ObjectPool FindPoolByUsedGameObject(GameObject go){if (go == null) return null;for (int i = 0; i < objectPoolsList.Count; i++){ObjectPool pool = objectPoolsList[i];for (int j = 0; j < pool.usedGameObjectList.Count; j++){if (pool.usedGameObjectList[j]==go){return pool;}}}return null;}/// <summary>/// 如果场景中没有对象池的父物体,则生成一个空物体作为所有对象池的父物体/// </summary>void CreatePoolsParentIfNull(){if (poolsParent == null){objectPoolsList.Clear();objectDictionary.Clear();poolsParent = new GameObject(poolsParentName);}}/// <summary>/// 先通过预制体查找它所属的小对象池,如果找到了,则返回这个小对象池/// 如果找不到,则创建一个小对象池,用来存放这种预制体/// </summary>/// <returns></returns>ObjectPool FindPoolByPrefabOrCreatePool(GameObject prefab){//确保大对象池存在CreatePoolsParentIfNull();//查找并返回该预制体对象的对象池ObjectPool objectPool = FindPoolByPrefab(prefab);if (objectPool == null){objectPool = new GameObject($"ObjectPool{prefab.name}").AddComponent<ObjectPool>();objectPool.prefabs = prefab;objectPool.transform.SetParent(poolsParent.transform);objectPoolsList.Add(objectPool);}return objectPool;}/// <summary>/// 查找并返回该预制体对象的对象池/// </summary>ObjectPool FindPoolByPrefab(GameObject prefab){if (prefab == null) return null;for (int i = 0; i < objectPoolsList.Count; i++){if (objectPoolsList[i].prefabs == prefab){return objectPoolsList[i];}}return null;}
}

物体身上最好写一个这样的方法将物体状态初始化,清楚一些脏数据

void OnDespawn()
    {
        transform.position = Vector3.zero;
        GetComponent<Rigidbody>().velocity = Vector3.zero;
    }

 

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

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

相关文章

下载安装并使用小乌龟TortoiseGit

1、下载TortoiseGit安装包 官网&#xff1a;Download – TortoiseGit – Windows Shell Interface to Githttps://tortoisegit.org/download/ 2、小乌龟汉化包 在官网的下面就有官方提供的下载包 3、安装

Electron入门,项目运行,只需四步轻松搞定。

electron 简单介绍&#xff1a; 实现&#xff1a;HTML/CSS/JS桌面程序&#xff0c;搭建跨平台桌面应用。 electron 官方文档&#xff1a; [https://electronjs.org/docs] 本文是基于以下2篇文章且自行实践过的&#xff0c;可行性真实有效。 文章1&#xff1a; https://www.cnbl…

Django学习笔记(2)

创建app 属于自动执行了python manage.py 直接在里面运行startapp app01就可以创建app01的项目了 之后在setting.py中注册app01 INSTALLED_APPS ["django.contrib.admin","django.contrib.auth","django.contrib.contenttypes","django.c…

合并jar包导致gradle传递依赖失效

目录 零、背景一、合并jar包1.1、自定义一组jar包1.2、自定义合并jar的任务1.3、定义打包jar的任务 二、发布jar包2.1、未合并jar包之前的合并方式2.2、合并jar包之后的合并方式 三、发现问题3.1、确定gradle中的依赖关系3.2、对比maven是否缺失依赖3.3、对比合并前后的pom.xml…

Source Insight配置Cppcheck做静态测试(Windows)

1.安装cppcheck 先从cppcheck官方网站下载cppcheck的安装包。 注&#xff1a; &#xff08;1&#xff09;官网地址&#xff1a;https://sourceforge.net/projects/cppcheck &#xff08;2&#xff09;截止2023年8月&#xff0c;官方发布的最新版本是cppcheck-2.11-x64-Setup.…

子集-回溯方法

class Solution {//题解思路//LinkedList<Integer> path new LinkedList<>(); List<List<Integer>> results new ArrayList<>();public List<List<Integer>> subsets(int[] nums) {//主方法中调用方法同时传入指定的参数初始值bac…

【数据挖掘】使用 Python 分析公共数据【01/10】

一、说明 本文讨论了如何使用 Python 使用 Pandas 库分析官方 COVID-19 病例数据。您将看到如何从实际数据集中收集见解&#xff0c;发现乍一看可能不那么明显的信息。特别是&#xff0c;本文中提供的示例说明了如何获取有关疾病在不同国家/地区传播速度的信息。 二、准备您的…

【计算机视觉|生成对抗】改进的生成对抗网络(GANs)训练技术

本系列博文为深度学习/计算机视觉论文笔记&#xff0c;转载请注明出处 标题&#xff1a;Improved Techniques for Training GANs 链接&#xff1a;[1606.03498v1] Improved Techniques for Training GANs (arxiv.org) 摘要 本文介绍了一系列应用于生成对抗网络&#xff08;G…

ICCV23 | Ada3D:利用动态推理挖掘3D感知任务中数据冗余性

​ 论文地址&#xff1a;https://arxiv.org/abs/2307.08209 项目主页&#xff1a;https://a-suozhang.xyz/ada3d.github.io/ 01. 背景与动因 3D检测(3D Detection)任务是自动驾驶任务中的重要任务。由于自动驾驶任务的安全性至关重要(safety-critic)&#xff0c;对感知算法的延…

HCIP STP总结

网桥的4个选举 根网桥&#xff1a; 有且仅有一台&#xff0c;且由BPDU中的桥ID来决定 桥ID 网桥优先级&#xff08;0-65535公有&#xff09; 默认32768 MAC地址&#xff08;只有存在svi接口…

Pinia基础教程

Pinia wiki Pinia 起始于 2019 年 11 月左右的一次实验&#xff0c;其目的是设计一个拥有组合式 API 的 Vue 状态管理库。从那时起&#xff0c;我们就倾向于同时支持 Vue 2 和 Vue 3&#xff0c;并且不强制要求开发者使用组合式 API&#xff0c;我们的初心至今没有改变。除了安…

数据结构-->栈

&#x1f495;休对故人思故国&#xff0c;且将新火试新茶&#xff0c;诗酒趁年华&#x1f495; 作者&#xff1a;Mylvzi 文章主要内容&#xff1a;详解链表OJ题 前言&#xff1a; 前面已经学习过顺序表&#xff0c;链表。他们都是线性表&#xff0c;今天要学习的栈也是一种线…

【C++】C 语言 和 C++ 语言中 const 关键字分析 ② ( const 常量分配内存时机 | const 常量在编译阶段分配内存 )

文章目录 一、const 常量内存分配时机二、使用如下代码验证 const 常量内存分配时机三、分析验证结果 - const 常量在编译阶段分配内存 一、const 常量内存分配时机 在上一篇博客中 , 讲到了获取 const 常量的地址 , 代码如下 : // 定义常量// 该常量定义在了 符号表 中// 符号…

C++--深度理解智能指针

PS:智能指针简单应用看这里 http://t.csdn.cn/qN7IK 1.智能指针的介绍 在C中&#xff0c;智能指针有三个版本&#xff0c;分别为&#xff1a; auto_ptr unique_ptr shared_ptr 这三个版本的智能指针中&#xff0c;shared_ptr最为完善&#xff0c;auto_ptr基本上没有太大用…

leetcode 213. 打家劫舍 II

2023.8.20 本题是 打家劫舍 的进阶版&#xff0c;房屋之间形成一个环了&#xff0c;也就是第一个房屋和最后一个房屋不能一起偷了。那么能偷的情况分为下列三种&#xff1a; 不考虑偷首房间。不考虑偷尾房间。不考虑偷首尾房间。 第三种情况包含于第一和第二种情况了&#xff…

【vue3】对axios进行封装,方便更改路由并且可以改成局域网ip访问(附代码)

对axios封装是在main.js里面进行封装&#xff0c;因为main.js是一个vue项目的入口 步骤&#xff1a; 在1处创建一个axios实例为http&#xff0c;baseURL是基础地址&#xff08;根据自己的需求写&#xff09;&#xff0c;写了这个在vue界面调用后端接口时只用在post请求处写路由…

Docker实战:Docker常用命令

一、镜像相关 1.1、查看镜像 docker images1.2、拉取镜像 docker pull nginx1.3、保存镜像 docker save -o nginx.tar nginx:latest1.4、移除镜像 docker rmi -f nginx:latest1.5、导入镜像 docker load -i nginx.tar二、容器相关 2.1、启动容器 docker run --name red…

每天一道leetcode:934. 最短的桥(图论中等广度优先遍历)

今日份题目&#xff1a; 给你一个大小为 n x n 的二元矩阵 grid &#xff0c;其中 1 表示陆地&#xff0c;0 表示水域。 岛 是由四面相连的 1 形成的一个最大组&#xff0c;即不会与非组内的任何其他 1 相连。grid 中 恰好存在两座岛 。 你可以将任意数量的 0 变为 1 &#…

基于X86六轮差速移动机器人运动控制器设计与实现(二)规划控制算法

带输入约束的 MPC 路径跟踪控制 MPC 算法是一种基于控制对象模型的控制方法&#xff0c;其优势在于在控制中考虑了 系统的多种物理约束&#xff0c;同时基于模型与当前机器人的反馈信息预估出未来机器人 位姿信息的处理方法可以解决控制迟滞的问题。 4.1 MPC 路径跟踪控…

iOS 17 正式版预计 9 月中下旬发布,部分新功能延后推出

苹果公司预计将在 9 月中下旬推出 iOS 17 正式版&#xff0c;iPhone XS 及更新的机型可免费更新。这次更新包含了许多新功能&#xff0c;但是根据苹果公司的网站显示&#xff0c;并不是所有的功能都会立即可用。苹果表示有一些功能“将在今年晚些时候推出”&#xff0c;比如&am…