Unity3D仿星露谷物语开发41之创建池管理器

news2025/5/13 12:00:41

1、目标

在PersistentScene中创建池管理器(Pool Manager)。这将允许一个预制对象池被创建和重用。

在游戏中当鼠标点击地面时,便会启用某一个对象。比如点击地面,就创建了一棵树,而这棵树是从预制体对象池中获取的(并且最大数量有限)。

2、池管理器

(1)概念

对象池通常用于频繁或快速生成的游戏对象,如游戏中的子弹。

什么是池管理器,以及它们为什么有用?

  • 对象池是指在场景中有一组“池化”对象,在需要时可以启用它们,不需要时可以禁用它们。
  • 这避免了创建新对象和销毁不再需要的对象
  • 反复创建新对象和销毁旧对象会消耗大量资源,并引发问题,例如增加“垃圾”回收量。当系统试图清理反复分配的未使用内存时,这可能会在游戏运行中导致掉帧。
  • 通过使用“池”中的对象,并在不再需要时将其返回池中,可以减少这些性能问题。

(2)创建流程

(3)使用池对象

3、创建PoolManager.cs脚本

在Assets -> Scripts 下新建目录命名为VFX,在此目录下创建新脚本命名为PoolManager。

 代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PoolManager : SingletonMonobehaviour<PoolManager>
{
    private Dictionary<int, Queue<GameObject>> poolDictionary = new Dictionary<int, Queue<GameObject>>();
    [SerializeField] private Pool[] pool = null;   // 池数组,每个值为预制体和个数。
    [SerializeField] private Transform objectPoolTransform = null;  // 用于存储对象池的父 Transform 

    [System.Serializable]
    public struct Pool
    {
        public int poolSize;
        public GameObject prefab;
    }

    private void Start()
    {
        // Create object pools on start
        for(int i = 0; i < pool.Length; i++)
        {
            CreatePool(pool[i].prefab, pool[i].poolSize);
        }
    }

    private void CreatePool(GameObject prefab, int poolSize)
    {
        int poolKey = prefab.GetInstanceID();
        string prefabName = prefab.name; // get prefab name

        GameObject parentGameObject = new GameObject(prefabName + "Anchor"); // 创建一个新的游戏对象作为该对象池所有游戏对象的父对象,并将其设置为objectPoolTransform的子对象。
        parentGameObject.transform.SetParent(objectPoolTransform);

        if (!poolDictionary.ContainsKey(poolKey))
        {
            poolDictionary.Add(poolKey, new Queue<GameObject>());

            for(int i = 0; i < poolSize; i++)
            {
                GameObject newObject = Instantiate(prefab, parentGameObject.transform) as GameObject;
                newObject.SetActive(false);

                poolDictionary[poolKey].Enqueue( newObject );
            }
        }
    }

    public GameObject ReuseObject(GameObject prefab, Vector3 position, Quaternion rotation)
    {
        int poolKey = prefab.GetInstanceID() ;

        if (poolDictionary.ContainsKey(poolKey))
        {
            // Get object from pool queue
            GameObject objectToReuse = GetObjectFromPool(poolKey);

            ResetObject(position, rotation, objectToReuse, prefab);

            return objectToReuse;
        }
        else
        {
            Debug.Log("No object pool for " + prefab);
            return null;
        }
    }

    private GameObject GetObjectFromPool(int poolKey)
    {
        GameObject objectToReuse = poolDictionary[poolKey].Dequeue();
        poolDictionary[poolKey].Enqueue(objectToReuse);

        // log to console if object is currently active
        if(objectToReuse.activeSelf == true) // objectToReuse.activeSelf 是 GameObject 类的一个属性,用于检查该对象当前是否处于激活状态。
        {
            objectToReuse.SetActive(false); // 确保返回的对象处于非激活状态,以便后续可以根据需要重新激活使用。
        }

        return objectToReuse;
    }

    private static void ResetObject(Vector3 position, Quaternion rotation, GameObject objectToReuse, GameObject prefab)
    {
        objectToReuse.transform.position = position;
        objectToReuse.transform.rotation = rotation;

        objectToReuse.transform.localScale = prefab.transform.localScale;
    }
}

4、创建池对象

在Hierarchy -> PersistentScene下创建空物体命名为PoolManager。

给PoolManager对象添加PoolManager组件,设置Pool为1,同时将Transform组件拖到Object Pool Transform中。

然后,在Assets -> Prefabs -> Scenary中,复制CanyonOakScenary预制体并且命名为TestObjectPoolCanyonOak。在Element0中,设置Pool Size为20,再把TestObjectPoolCanyonOak拖入到Prefab选项中。

点击TestObjectPoolCanyonOak预制体,删除它和Trunk的Obscuringxxx组件。

5、修改Player.cs脚本

实现测试功能:当鼠标右击时,启用一个Pool中的预制体。

在最开始的变量定义中添加代码:

public GameObject canyonOakTreePrefab;

在PlayerTestInput函数中添加如下功能:

// Test object pool
if (Input.GetMouseButtonDown(1))
{
    GameObject tree = PoolManager.Instance.ReuseObject(canyonOakTreePrefab, mainCamera.ScreenToWorldPoint(new Vector3(Input.mousePosition.x,
        Input.mousePosition.y, -mainCamera.transform.position.z)), Quaternion.identity);
    tree.SetActive(true);
}

在Unity中,配置Player脚本的canyonOakTreePrefab信息。

注解:此时配置canyonOakTreePrefab信息,主要是通过int poolKey = prefab.GetInstanceID() ;获取poolKey信息,然后从Pool池中获取对象。

6、运行游戏

每次右击鼠标时,都会产生一棵树,同时最多只有20棵树(这些树会被重复利用)。

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

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

相关文章

Modbus协议介绍

Modbus是一种串行通信协议&#xff0c;由Modicon公司&#xff08;现为施耐德电气&#xff09;在1979年为可编程逻辑控制器&#xff08;PLC&#xff09;通信而开发。它是工业自动化领域最常用的通信协议之一&#xff0c;具有开放性、简单性和跨平台兼容性&#xff0c;广泛应用于…

I/O多路复用(select/poll/epoll)

通过一个进程来维护多个Socket&#xff0c;也就是I/O多路复用&#xff0c;是一种常见的并发编程技术&#xff0c;它允许单个线程或进程同时监视多个输入/输出&#xff08;I/O&#xff09;流&#xff08;例如网络连接、文件描述符&#xff09;。当任何一个I/O流准备好进行读写操…

Westlake-Omni 情感端音频生成式输出模型

简述 github地址在 GitHub - xinchen-ai/Westlake-OmniContribute to xinchen-ai/Westlake-Omni development by creating an account on GitHub.https://github.com/xinchen-ai/Westlake-Omni Westlake-Omni 是由西湖心辰&#xff08;xinchen-ai&#xff09;开发的一个开源…

随手记录5

一些顶级思维&#xff1a; ​ 顶级思维 1、永远不要自卑。 也永远不要感觉自己比别人差&#xff0c;这个人有没有钱&#xff0c;有多少钱&#xff0c;其实跟你都没有关系。有很多人就是那个奴性太强&#xff0c;看到比自己优秀的人&#xff0c;甚至一些装逼的人&#xff0c;这…

Linux驱动:驱动编译流程了解

要求 1、开发板中的linux的zImage必须是自己编译的 2、内核源码树,其实就是一个经过了配置编译之后的内核源码。 3、nfs挂载的rootfs,主机ubuntu中必须搭建一个nfs服务器。 内核源码树 解压 tar -jxvf x210kernel.tar.bz2 编译 make x210ii_qt_defconfigmakeCan’t use ‘…

使用 Flowise 构建基于私有知识库的智能客服 Agent(图文教程)

使用 Flowise 构建基于私有知识库的智能客服 Agent(图文教程) 在构建 AI 客服时,常见的需求是让机器人基于企业自身的知识文档,提供准确可靠的答案。本文将手把手教你如何使用 Flowise + 向量数据库(如 Pinecone),构建一个结合 RAG(Retrieval-Augmented Generation)检…

RabbitMQ ③-Spring使用RabbitMQ

Spring使用RabbitMQ 创建 Spring 项目后&#xff0c;引入依赖&#xff1a; <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-amqp --> <dependency><groupId>org.springframework.boot</groupId><artifac…

linux中常用的命令(四)

目录 1-cat查看文件内容 2-more命令 3-less命令 4-head命令 5-tail命令 1-cat查看文件内容 cat中的一些操作 -b : 列出行号&#xff08;不含空白行&#xff09;-E : 将结尾的断行以 $ 的形式展示出来-n : 列出行号&#xff08;含空白行&#xff09;-T : 将 tab 键 以 ^I 显示…

利用SSRF击穿内网!kali靶机实验

目录 1. 靶场拓扑图 2. 判断SSRF的存在 3. SSRF获取本地信息 3.1. SSRF常用协议 3.2. 使用file协议 4. 172.150.23.1/24探测端口 5. 172.150.23.22 - 代码注入 6. 172.150.23.23 SQL注入 7. 172.150.23.24 命令执行 7.1. 实验步骤 8. 172.150.23.27:6379 Redis未授权…

DVWA在线靶场-xss部分

目录 1. xxs&#xff08;dom&#xff09; 1.1 low 1.2 medium 1.3 high 1.4 impossible 2. xss&#xff08;reflected&#xff09; 反射型 2.1 low 2.2 medium 2.3 high 2.4 impossible 3. xss&#xff08;stored&#xff09;存储型 --留言板 3.1 low 3.2 medium 3.3 high 3.…

Go 语言 slice(切片) 的使用

序言 在许多开发语言中&#xff0c;动态数组是必不可少的一个组成部分。在实际的开发中很少会使用到数组&#xff0c;因为对于数组的大小大多数情况下我们是不能事先就确定好的&#xff0c;所以他不够灵活。动态数组通过提供自动扩容的机制&#xff0c;极大地提升了开发效率。这…

js常用的数组遍历方式

以下是一个完整的示例&#xff0c;将包含图片、文字和数字的数组渲染到 HTML 页面&#xff0c;使用 ​多种遍历方式​ 实现不同的渲染效果&#xff1a; 1. 准备数据&#xff08;数组&#xff09; const items [{ id: 1, name: "苹果", price: 5.99, image: "h…

【网络编程】五、三次握手 四次挥手

文章目录 Ⅰ. 三次握手Ⅱ. 建立连接后的通信Ⅲ. 四次挥手 Ⅰ. 三次握手 ​ 1、首先双方都是处于未通信的状态&#xff0c;也就是关闭状态 CLOSE。 ​ 2、因为服务端是为了服务客户端的&#xff0c;所以它会提前调用 listen() 函数进行对客户端请求的监听。 ​ 3、接着客户端就…

从 AGI 到具身智能体:解构 AI 核心概念与演化路径全景20250509

&#x1f916; 从 AGI 到具身智能体&#xff1a;解构 AI 核心概念与演化路径全景 作者&#xff1a;AI 应用实践者 在过去的几年中&#xff0c;AI 领域飞速发展&#xff0c;从简单的文本生成模型演进为今天具备复杂推理、感知能力的“智能体”系统。本文将从核心概念出发&#x…

Docker Compose 的历史和发展

这张图表展示了Docker Compose从V1到V2的演变过程&#xff0c;并解释了不同版本的Compose文件格式及其支持情况。以下是对图表的详细讲解&#xff1a; Compose V1 No longer supported: Compose V1已经不再支持。Compose file format 3.x: 使用了版本3.x的Compose文件格式。 …

从 JIT 即时编译一直讲到CGI|FastGGI|WSGI|ASGI四种协议的实现细节

背景 我一度理解错了这个东西&#xff0c;之前没有AI的时候&#xff0c;也没深究过&#xff0c;还觉得PHP8支持了常驻内存的运行的错误理解&#xff0c;时至今日再来看这个就很清晰了。 另外&#xff0c;早几年对以上4个协议&#xff0c;我也没搞懂&#xff0c;时至今日&…

CSS3 遮罩

在网页设计中&#xff0c;我们经常需要实现一些特殊的视觉效果来增强用户体验。CSS3 遮罩&#xff08;mask&#xff09;允许我们通过控制元素的可见区域来创建各种精美的视觉效果。本文将带你全面了解 CSS3 遮罩的功能和应用。 什么是 CSS3 遮罩&#xff1f; CSS3 遮罩是一种…

ResNet残差神经网络的模型结构定义(pytorch实现)

ResNet残差神经网络的模型结构定义&#xff08;pytorch实现&#xff09; ResNet‑34 ResNet‑34的实现思路。核心在于&#xff1a; 定义残差块&#xff08;BasicBlock&#xff09;用 _make_layer 方法堆叠多个残差块按照 ResNet‑34 的通道和层数配置来搭建网络 import torch…

uniapp|商品列表加入购物车实现抛物线动画效果、上下左右抛入、多端兼容(H5、APP、微信小程序)

以uniapp框架为基础,详细解析商品列表加入购物车抛物线动画的实现方案。通过动态获取商品点击位置与购物车坐标,结合CSS过渡动画模拟抛物线轨迹,实现从商品图到购物车图标的动态效果。 目录 核心实现原理坐标动态计算抛物线轨迹模拟​动画元素控制代码实现详解模板层设计脚本…

谈AI/OT 的融合

过去的十几年间&#xff0c;工业界讨论最多的话题之一就是IT/OT 融合&#xff0c;现在&#xff0c;我们不仅要实现IT/OT 的融合&#xff0c;更要面向AI/OT 的融合。看起来不太靠谱&#xff0c;却留给我们无限的想象空间。OT 领域的专家们不要再当“九斤老太”&#xff0c;指责这…