当前位置: 首页 > 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;…...

云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?

大家好&#xff0c;欢迎来到《云原生核心技术》系列的第七篇&#xff01; 在上一篇&#xff0c;我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在&#xff0c;我们就像一个拥有了一块崭新数字土地的农场主&#xff0c;是时…...

3.3.1_1 检错编码(奇偶校验码)

从这节课开始&#xff0c;我们会探讨数据链路层的差错控制功能&#xff0c;差错控制功能的主要目标是要发现并且解决一个帧内部的位错误&#xff0c;我们需要使用特殊的编码技术去发现帧内部的位错误&#xff0c;当我们发现位错误之后&#xff0c;通常来说有两种解决方案。第一…...

零基础设计模式——行为型模式 - 责任链模式

第四部分&#xff1a;行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习&#xff01;行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想&#xff1a;使多个对象都有机会处…...

图表类系列各种样式PPT模版分享

图标图表系列PPT模版&#xff0c;柱状图PPT模版&#xff0c;线状图PPT模版&#xff0c;折线图PPT模版&#xff0c;饼状图PPT模版&#xff0c;雷达图PPT模版&#xff0c;树状图PPT模版 图表类系列各种样式PPT模版分享&#xff1a;图表系列PPT模板https://pan.quark.cn/s/20d40aa…...

【Go语言基础【13】】函数、闭包、方法

文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数&#xff08;函数作为参数、返回值&#xff09; 三、匿名函数与闭包1. 匿名函数&#xff08;Lambda函…...

Kubernetes 网络模型深度解析:Pod IP 与 Service 的负载均衡机制,Service到底是什么?

Pod IP 的本质与特性 Pod IP 的定位 纯端点地址&#xff1a;Pod IP 是分配给 Pod 网络命名空间的真实 IP 地址&#xff08;如 10.244.1.2&#xff09;无特殊名称&#xff1a;在 Kubernetes 中&#xff0c;它通常被称为 “Pod IP” 或 “容器 IP”生命周期&#xff1a;与 Pod …...

ZYNQ学习记录FPGA(一)ZYNQ简介

一、知识准备 1.一些术语,缩写和概念&#xff1a; 1&#xff09;ZYNQ全称&#xff1a;ZYNQ7000 All Pgrammable SoC 2&#xff09;SoC:system on chips(片上系统)&#xff0c;对比集成电路的SoB&#xff08;system on board&#xff09; 3&#xff09;ARM&#xff1a;处理器…...

机器学习的数学基础:线性模型

线性模型 线性模型的基本形式为&#xff1a; f ( x ) ω T x b f\left(\boldsymbol{x}\right)\boldsymbol{\omega}^\text{T}\boldsymbol{x}b f(x)ωTxb 回归问题 利用最小二乘法&#xff0c;得到 ω \boldsymbol{\omega} ω和 b b b的参数估计$ \boldsymbol{\hat{\omega}}…...

数据库——redis

一、Redis 介绍 1. 概述 Redis&#xff08;Remote Dictionary Server&#xff09;是一个开源的、高性能的内存键值数据库系统&#xff0c;具有以下核心特点&#xff1a; 内存存储架构&#xff1a;数据主要存储在内存中&#xff0c;提供微秒级的读写响应 多数据结构支持&…...

用 Rust 重写 Linux 内核模块实战:迈向安全内核的新篇章

用 Rust 重写 Linux 内核模块实战&#xff1a;迈向安全内核的新篇章 ​​摘要&#xff1a;​​ 操作系统内核的安全性、稳定性至关重要。传统 Linux 内核模块开发长期依赖于 C 语言&#xff0c;受限于 C 语言本身的内存安全和并发安全问题&#xff0c;开发复杂模块极易引入难以…...