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

Unity学习笔记--如何优雅简便地利用对象池生成游戏对象(进阶版)LRU + 对象池

前言

之前写过一篇关于对象池的文章,现在来看写的并不是很好,所以来考虑优化下。

现在来看一年前写的代码,越看越不能入目hhh

Unity学习笔记–如何优雅简便地利用对象池生成游戏对象

前置知识

Unity学习笔记–使用 C# 开发一个 LRU

代码实现

PoolManager.cs

using System;
using System.Collections.Generic;
using Factory;namespace ToolManager
{public class PoolManager{private Dictionary<string, LinkedListNode<Tuple<string, Pool>>> lru_dict;   // Key : pool_name == obj_nameprivate LinkedList<Tuple<string, Pool>> cache;private int capacity;public PoolManager(int capacity_in = 64){capacity = capacity_in;cache = new LinkedList<Tuple<string, Pool>>();lru_dict = new Dictionary<string, LinkedListNode<Tuple<string, Pool>>>();}public bool HasPool(string path){return lru_dict.ContainsKey(path);}public bool AddPool(BaseFactory factory, int init_count = 0){string pool_name = factory.GetObjPath();if (HasPool(pool_name)){return false;}Pool pool = new Pool(this, pool_name, factory, init_count);LinkedListNode<Tuple<string, Pool>> node = new LinkedListNode<Tuple<string, Pool>>(Tuple.Create(pool_name, pool));LRUAdd(node);return true;}public bool DelPool(string name){if (!HasPool(name)){return false;}var node = lru_dict[name];GetPool(node).ReleasePool();LRURemove(node);return true;}public object PopOne(string name){object res = null;if (HasPool(name)){var node = lru_dict[name];LRUChange(node);Pool pool = GetPool(node);res = pool.PopOne();LRURemove(node);}return res;}public object[] Pop(string name, int count){object[] res = null;if (HasPool(name)){var node = lru_dict[name];LRUChange(node);Pool pool = GetPool(node);res = pool.Pop(count);LRURemove(node);}return res;}public void PushOne(string name, object obj){if (HasPool(name)){var node = lru_dict[name];LRUChange(node);GetPool(node).PushOne(obj);RefreshLRU();}}public void Push(string name, object[] objs){if (HasPool(name)){var node = lru_dict[name];LRUChange(node);GetPool(node).Push(objs);RefreshLRU();}}private Pool GetPool(LinkedListNode<Tuple<string, Pool>> node){return node.Value.Item2;}// ------------------------- LRU Function -------------------------private void LRUChange(LinkedListNode<Tuple<string, Pool>> node){cache.Remove(node);cache.AddLast(node);}private void LRUAdd(LinkedListNode<Tuple<string, Pool>> node){lru_dict.Add(node.Value.Item1, node);cache.AddLast(node);}private void LRURemove(LinkedListNode<Tuple<string, Pool>> node){cache.Remove(node);lru_dict.Remove(node.Value.Item1);}private void RefreshLRU(){int lru_count = LRUCacheCount;while (lru_count > capacity){Pool pool = GetPool(cache.First);int n_objects_to_remove = Math.Min(pool.PoolCount, lru_count - capacity);for (int i = 0; i < n_objects_to_remove; i++){pool.ReleaseOne();}if(pool.PoolCount == 0){DelPool(pool.pool_name);}lru_count = LRUCacheCount;}}private int LRUCacheCount{get{int count = 0;foreach (var node in lru_dict.Values){count += node.Value.Item2.PoolCount;}return count;}}private class Pool{private PoolManager pool_mgr;private BaseFactory factory;private Queue<object> queue;public string pool_name;public Pool(PoolManager pool_mgr_in, string pool_name_in, BaseFactory factory_in, int init_count_in){pool_mgr = pool_mgr_in;pool_name = pool_name_in;factory = factory_in;queue = new Queue<object>();InitPool(init_count_in);}private void InitPool(int init_count){for (int i = 0; i < init_count; i++){queue.Enqueue(factory.CreateObject());}}public void ReleasePool(){foreach (var obj in queue){factory.DestroyObject(obj);}queue.Clear();factory.ReleaseFactory();}public object PopOne(){if (queue.Count > 0){object obj = queue.Dequeue();factory.ResetObject(obj);return obj;}return factory.CreateObject();}public object[] Pop(int count){object[] objs = new object[count];for (int i = 0; i < count; i++){objs[i] = PopOne();}return objs;}public void PushOne(object obj){factory.RecycleObject(obj);queue.Enqueue(obj);}public void Push(object[] objs){foreach (var obj in objs){PushOne(obj);}}public void ReleaseOne(){factory.DestroyObject(queue.Dequeue());}public int PoolCount { get => queue.Count; }}}
}

BaseFactory.cs

namespace Factory
{public abstract class BaseFactory{protected string obj_path;public BaseFactory(string obj_path_in){obj_path = obj_path_in;}public abstract object CreateObject();public abstract void ResetObject(object obj);public abstract void RecycleObject(object obj);public abstract void DestroyObject(object obj);public abstract void ReleaseFactory();public virtual string GetObjPath(){return obj_path;}}
}

使用

创建 Factory

using Factory;public class BulletFactory : BaseFactory
{public BulletFactory(string obj_path_in) : base(obj_path_in){}public override object CreateObject(){Bullet bullet = new Bullet(obj_path);bullet.ReuseInit();return bullet;}public override void DestroyObject(object obj){((Bullet)obj).Destroy();}public override void RecycleObject(object obj){((Bullet)obj).Recycle();}public override void ReleaseFactory(){}public override void ResetObject(object obj){((Bullet)obj).ReuseInit();}
}

创建 object

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Bullet
{private GameObject go;private string path;private static GameObject prefab;public Bullet(string path_in){path = path_in;if (prefab == null){prefab = (GameObject) Resources.Load(path);}}public void ReuseInit(){if (go){go.SetActive(true);}else{go = GameObject.Instantiate(prefab);}go.GetComponent<RecycleMe>().DelayCall(1, Func);}public void Destroy(){GameObject.Destroy(go);}public void Recycle(){go.SetActive(false);}private void Func(){BulletManager.Ins.PushOne(path, this);}
}

创建 BulletManager

BulletManager.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using ToolManager;public class BulletManager : MonoBehaviour
{private PoolManager pool_mgr;private static BulletManager _ins;public static BulletManager Ins{get => _ins;}private void Awake(){Init();}private void Init(){_ins = this;pool_mgr = new PoolManager();}public void PushOne(string path, Bullet obj){if (!pool_mgr.HasPool(path)){pool_mgr.AddPool(new BulletFactory(path));}pool_mgr.PushOne(path, obj);}public Bullet PopOne(string path){if (!pool_mgr.HasPool(path)){pool_mgr.AddPool(new BulletFactory(path));}Bullet bullet = (Bullet)pool_mgr.PopOne(path);return bullet;}
}

验证

为了验证,我写了一个 ShootManager.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class ShootManager : MonoBehaviour
{private List<Bullet> bullet_list;private string path = "Bullet";private static ShootManager _ins;public static ShootManager Ins{get => _ins;}private void Awake(){Init();}private void Init(){_ins = this;bullet_list = new List<Bullet>();}private void Update(){if (Input.GetMouseButtonDown(0)){bullet_list.Add(BulletManager.Ins.PopOne(path));}}
}

创建之后过 1s 之后回收自己。
RecycleMe.cs

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class RecycleMe : MonoBehaviour
{public void DelayCall(float delay, Action func){StartCoroutine(DestroyAfterDelayCoroutine(delay, func));}IEnumerator DestroyAfterDelayCoroutine(float delay, Action func){yield return new WaitForSeconds(delay);func.Invoke();}}

效果

LRUPool

相关文章:

Unity学习笔记--如何优雅简便地利用对象池生成游戏对象(进阶版)LRU + 对象池

前言 之前写过一篇关于对象池的文章&#xff0c;现在来看写的并不是很好&#xff0c;所以来考虑优化下。 现在来看一年前写的代码&#xff0c;越看越不能入目hhh Unity学习笔记–如何优雅简便地利用对象池生成游戏对象 前置知识 Unity学习笔记–使用 C# 开发一个 LRU 代码实…...

【Spring专题】Bean的声明周期流程图

前言 我向来不主张【通过源码】理解业务&#xff0c;因为每个人的能力有限&#xff0c;甚至可能会因为阅读错误导致出现理解上的偏差&#xff0c;所以我决定&#xff0c;还是先帮大家【开天眼】&#xff0c;先整体看看流程图&#xff0c;好知道&#xff0c;Spring在写源码的过…...

C++实现俄罗斯方块(源码+详解)

&#x1f442; Take me Hand Acoustic - Ccile Corbel - 单曲 - 网易云音乐 源码Debug工具 &#xff08;1&#xff09;cppreference.com &#xff08;主&#xff09; &#xff08;2&#xff09;必应 (bing.com) &#xff08;3&#xff09;GPT&#xff08;主&#xff09; &#…...

01:STM32点灯大师和蜂鸣器

目录 一:点亮1个LED 1:连接图 2:函数介绍 3:点灯代码 二:LED闪烁 1:函数介绍 2:闪烁代码 三:LED流水灯 1:连接图 2:函数介绍 3:流水灯代码 四:蜂鸣器 1:连接图 2:蜂鸣器代码 一:点亮1个LED 1:连接图 因为IO口与LED负极相连所以IO口输出低电频,点亮LED (采用的是低…...

linux pwn 基础知识

环境搭建 虚拟机安装 镜像下载网站为了避免环境问题建议 22.04 &#xff0c;20.04&#xff0c;18.04&#xff0c;16.04 等常见版本 ubuntu 虚拟机环境各准备一份。注意定期更新快照以防意外。虚拟机建议硬盘 256 G 以上&#xff0c;内存也尽量大一些。硬盘大小只是上界&#…...

Unity Poisson分布 【由ChatGPT生成】

Unity Poisson分布 【由ChatGPT生成】 前言项目Unity场景布置代码编写添加并设置脚本运行效果总结 前言 在Unity游戏开发中&#xff0c;数学和统计学的概念常常用于解决各种问题&#xff0c;从资源分配到游戏机制的设计。本文将探讨Poisson分布在Unity游戏开发中的实际应用和作…...

permission denied while trying to connect to the Docker daemon socket 错误

安装 docker 执行错误如下&#xff1a; $ docker pspermission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get “http://%2Fvar%2Frun%2Fdocker.sock/v1.24/containers/json”: dial unix /var/run/docker.sock: connect:…...

pytorch nn.ModuleList和nn.Sequential的用法笔记

有部分内容转自: pytorch小记:nn.ModuleList和nn.Sequential的用法以及区别_慕思侣的博客-CSDN博客 但是有部分内容做了修改调整, 在构建网络的时候,pytorch有一些基础概念很重要,比如nn.Module,nn.ModuleList,nn.Sequential,这些类我们称为为容器(containers),可…...

SQL | 高级数据过滤

5-高级数据过滤 通过组合WHERE子句&#xff0c;建立功能更强的检索语句。 5.1-组合WHERE子句 前面写的都是单一条件下的WHERE子句&#xff0c;SQL语句允许给出多个WHERE子句来组合检索&#xff0c;这些WHERE子句通过AND子句或者OR子句进行连接。 操作符&#xff08;operato…...

ARM架构银河麒麟docker,源码编译安装GDAL

docker中安装依赖 sudo apt-get update sudo apt-get install build-essential autoconf automake libtool sudo apt-get install libproj-dev libgeos-dev libjson-c-dev libpng-dev libjpeg-dev sudo apt-get install python3-dev sudo apt-get install python3.11-dev去官网…...

(3)原神角色数据分析-3

绘图类 在名为“WRITEPHOT.py”的文件中&#xff0c;定义如下绘图方式&#xff0c;则在主页面(app.py)文件中&#xff0c;可通过如下方式调用&#xff1a; from WRITEPHOTO import WriteScatter,WriteFunnel,WriteBarData,WritePie,WriteLineBar 代码如下&#xff1a; "…...

skywalking日志收集

文章目录 一、介绍二、添加依赖三、修改日志配置1. 添加链路表示traceId2. 添加链路上下文3. 异步日志 四、收集链路日志 一、介绍 在上一篇文章skywalking全链路追踪中我们介绍了在微服务项目中使用skywalking进行服务调用链路的追踪。 本文在全链路追踪的基础上&#xff0c…...

ASL国产CS5212规格书 DP转VGA 替代RTD2166低成本方案 兼容IT6516设计原理图

CS5212可替代兼容瑞昱RTD2166和联阳T6516&#xff0c;ASL集睿致远这款芯片是一种高性能的DP显示端口到VGA转换器芯片。它结合了DisplayPort输入接口和模拟RGB DAC输出接口&#xff0c;嵌入式单片机基于工业标准8051核心。 CS5212适用于多个细分市场和显示器应用程序&#xff1…...

关于Jquery的Validate插件--rules添加自定义方法(强密码验证方法)

简介&#xff1a;请看菜鸟教程&#xff0c;根据给出的方法&#xff0c;自定义识别密码是否为复杂密码的方法 链接: https://www.runoob.com/jquery/jquery-plugin-validate.html Query Validate 插件为表单提供了强大的验证功能&#xff0c;让客户端表单验证变得更简单&#…...

股票自动交易接口开发原理及源码分享

股票自动交易接口的开发原理涉及多个方面&#xff0c;主要包括以下几个步骤&#xff1a; 1. 数据接口获取&#xff1a;通过连接到证券交易所或第三方数据提供商的API&#xff0c;获取实时市场数据&#xff0c;包括股票报价、交易成交量、买卖盘口等信息。 2. 策略定义&#x…...

2023/8/11题解

时间限制: 1000MS 内存限制: 65536KB 解题思路 建树 模拟 &#xff0c;复杂在于建树&#xff0c;此处从题目需求可知需要按层建树&#xff0c;所以需要队列模拟&#xff0c;查找比较容易就是普通的深搜 参考代码 #include<bits/stdc.h> using namespace std; vector<…...

构造函数

一、构造函数 构造函数用来在创建对象时初始化对象&#xff0c;为对象数据成员赋初始值。 类的数据成员是不能在类定义时初始化的&#xff0c;类定义并没有产生一个实体&#xff0c;而是给出了一个数据类型&#xff0c;不占用存储空间&#xff0c;无处容纳数据。 如果一个类…...

JS 原型与继承

本文内容学习于&#xff1a;后盾人 (houdunren.com) 一、原型对象 每个对象都有一个原型prototype对象&#xff0c;通过函数创建的对象也将拥有这个原型对象。 原型是一个指向对象的指针。 1.可以将原型理解为对象的父亲&#xff0c;对象从原型对象继承来属性 2.原型就是对象…...

解决 Oracle 数据库中表被锁问题的方案和方法

我们经常会遇到表被锁的情况&#xff0c;这可能会严重影响数据库的性能和可用性。我将与大家分享如何识别、分析和解决这些问题&#xff0c;以及如何使用特定的 SQL 查询来执行解锁操作。 了解表锁的原因 首先&#xff0c;让我们来了解一下导致表被锁的常见原因。长时间运行的…...

ORACLE行转列、列转行实现方式及案例

ORACLE行转列、列转行实现方式及案例 行转列案例方式1.PIVOT方式2.MAX和DECODE方式3.CASE WHEN和GROUP BY 列转行案例方式1.UNPIVOT方式2.UNION ALL 行转列 案例 假设我们有一个名为sales的表&#xff0c;其中包含了产品销售数据。表中有三列&#xff1a;product&#xff08;…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器

一.自适应梯度算法Adagrad概述 Adagrad&#xff08;Adaptive Gradient Algorithm&#xff09;是一种自适应学习率的优化算法&#xff0c;由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率&#xff0c;适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版​分享

平时用 iPhone 的时候&#xff0c;难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵&#xff0c;或者买了二手 iPhone 却被原来的 iCloud 账号锁住&#xff0c;这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...

1688商品列表API与其他数据源的对接思路

将1688商品列表API与其他数据源对接时&#xff0c;需结合业务场景设计数据流转链路&#xff0c;重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点&#xff1a; 一、核心对接场景与目标 商品数据同步 场景&#xff1a;将1688商品信息…...

2025盘古石杯决赛【手机取证】

前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来&#xff0c;实在找不到&#xff0c;希望有大佬教一下我。 还有就会议时间&#xff0c;我感觉不是图片时间&#xff0c;因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...

unix/linux,sudo,其发展历程详细时间线、由来、历史背景

sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...

Spring AI 入门:Java 开发者的生成式 AI 实践之路

一、Spring AI 简介 在人工智能技术快速迭代的今天&#xff0c;Spring AI 作为 Spring 生态系统的新生力量&#xff0c;正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务&#xff08;如 OpenAI、Anthropic&#xff09;的无缝对接&…...

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

爬虫基础学习day2

# 爬虫设计领域 工商&#xff1a;企查查、天眼查短视频&#xff1a;抖音、快手、西瓜 ---> 飞瓜电商&#xff1a;京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空&#xff1a;抓取所有航空公司价格 ---> 去哪儿自媒体&#xff1a;采集自媒体数据进…...

JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案

JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停​​ 1. ​​安全点(Safepoint)阻塞​​ ​​现象​​:JVM暂停但无GC日志,日志显示No GCs detected。​​原因​​:JVM等待所有线程进入安全点(如…...

从 GreenPlum 到镜舟数据库:杭银消费金融湖仓一体转型实践

作者&#xff1a;吴岐诗&#xff0c;杭银消费金融大数据应用开发工程师 本文整理自杭银消费金融大数据应用开发工程师在StarRocks Summit Asia 2024的分享 引言&#xff1a;融合数据湖与数仓的创新之路 在数字金融时代&#xff0c;数据已成为金融机构的核心竞争力。杭银消费金…...