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

Unity3D仿星露谷物语开发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 startfor(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 nameGameObject 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 queueGameObject 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 activeif(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.xdnf.cn/news/381709.html

相关文章:

  • 记录一次window2012r2安装配置oracle11g的过程-出现的错误以及解决方法
  • 谷歌学术链接
  • OSPF综合应用
  • Nginx高级配置
  • 解锁HBase:大数据存储的神秘之门
  • Linux:线程同步与互斥
  • 《Python星球日记》 第52天:反向传播与优化器
  • MySQL 数据类型全面指南:从理论到实践
  • HCIP笔记
  • Veins同时打开SUMO和OMNeT++的GUI界面
  • 基于Arduino Nano的DIY示波器
  • 2505d,d的借用检查器
  • 基于Spring Boot + Vue的母婴商城系统( 前后端分离)
  • InnoDB结构与表空间文件页的详解
  • 前端性能优化
  • Pycharm(二十)张量的运算与操作
  • Webug4.0靶场通关笔记-靶场搭建方法(3种方法)
  • Kubernetes生产实战(十三):灰度发布与蓝绿发布实战指南
  • 关于流媒体的知识总结
  • 全息美AISEO引领未来智能营销新趋势
  • SRP单一职责原则
  • 备战菊厂笔试3
  • short变量赋值为32768, 实际为什么是-32768?不同语言的不同进制字面量?字面量?编程语言的基本类型?
  • Java、Python、NodeJS等开发环境安装及配置镜像加速到国内源
  • .Net HttpClient 使用准则
  • 【脑机接口临床】脑机接口手术的风险?脑机接口手术的应用场景?脑机接口手术如何实现偏瘫康复?
  • RT-Thread 深入系列 Part 6:高性能与低功耗优化策略
  • 智能库室联管联控系统|智能兵器室门禁管理系统
  • AI日报 · 2025年5月10日|OpenAI“Stargate”超级数据中心项目掀起美国各州争夺战
  • Dify+Ollama+Deepseek+BGE-M3来搭建本地知识库实操