Unity3D对象池设计与实现详解

前言

在Unity3D中,对象池(Object Pooling)是一种优化技术,用于减少频繁实例化和销毁对象带来的性能开销。以下是对象池的详细设计和实现步骤:

对惹,这里有一个游戏开发交流小组,希望大家可以点击进来一起交流一下开发经验呀!

1. 核心原理

  • 预生成对象:预先创建一定数量的对象并存入池中。
  • 复用机制:需要时从池中取出对象,用完后回收,而非销毁。
  • 状态管理:对象回收时重置状态,确保下次使用时的正确性。

2. 应用场景

  • 频繁创建/销毁的对象(如子弹、敌人、特效)。
  • 移动设备或性能敏感场景。

3. 实现步骤

(1) 对象池管理器(ObjectPool)

  • 单例模式:全局访问点。
  • 字典存储池:按预制体分类管理不同对象池。
  • 实例映射:记录实例对应的预制体,用于回收时归类。
using UnityEngine;
using System.Collections.Generic;public class ObjectPool : MonoBehaviour
{public static ObjectPool Instance;private Dictionary<GameObject, Pool> _pools = new Dictionary<GameObject, Pool>();private Dictionary<GameObject, GameObject> _instanceToPrefabMap = new Dictionary<GameObject, GameObject>();void Awake(){Instance = this;}
}

(2) 池对象管理(Pool类)

  • 队列存储:使用Queue高效管理可用对象。
  • 动态扩展:当池为空时按需创建新对象。
  • 状态重置:通过接口IPoolable自定义回收逻辑。
[System.Serializable]
private class Pool
{public GameObject Prefab;public int InitialSize = 10;private Queue<GameObject> _available = new Queue<GameObject>();public Pool(GameObject prefab, int initialSize){Prefab = prefab;InitialSize = initialSize;Initialize();}private void Initialize(){for (int i = 0; i < InitialSize; i++){AddObject();}}private GameObject AddObject(bool isActive = false){GameObject obj = Object.Instantiate(Prefab);obj.SetActive(isActive);_available.Enqueue(obj);return obj;}public GameObject Get(){if (_available.Count == 0)AddObject();GameObject obj = _available.Dequeue();obj.SetActive(true);// 调用自定义初始化逻辑IPoolable poolable = obj.GetComponent<IPoolable>();poolable?.OnGet();return obj;}public void Return(GameObject obj){// 调用自定义回收逻辑IPoolable poolable = obj.GetComponent<IPoolable>();poolable?.OnReturn();obj.SetActive(false);_available.Enqueue(obj);}
}

(3) 全局接口方法

  • 获取对象GetObject(prefab)
  • 回收对象ReturnObject(obj)
public GameObject GetObject(GameObject prefab)
{if (!_pools.ContainsKey(prefab))_pools[prefab] = new Pool(prefab, 10);GameObject obj = _pools[prefab].Get();_instanceToPrefabMap[obj] = prefab;return obj;
}public void ReturnObject(GameObject obj)
{if (_instanceToPrefabMap.ContainsKey(obj)){GameObject prefab = _instanceToPrefabMap[obj];_pools[prefab].Return(obj);_instanceToPrefabMap.Remove(obj);}else{Object.Destroy(obj);}
}

4. 自定义对象逻辑(IPoolable接口)

  • 定义接口:对象实现OnGet()OnReturn()以处理状态重置。
public interface IPoolable
{void OnGet();   // 被取出时的初始化void OnReturn(); // 被回收时的清理
}

示例:子弹对象

public class Bullet : MonoBehaviour, IPoolable
{private Rigidbody _rb;void Awake(){_rb = GetComponent<Rigidbody>();}public void OnGet(){_rb.velocity = Vector3.zero;_rb.AddForce(transform.forward * 1000f);}public void OnReturn(){_rb.velocity = Vector3.zero;}
}

5. 使用示例

// 生成子弹
GameObject bullet = ObjectPool.Instance.GetObject(bulletPrefab);
bullet.transform.position = transform.position;// 回收子弹(如碰撞后)
ObjectPool.Instance.ReturnObject(bullet);

6. 高级优化

  • 预加载池:在场景加载时初始化常用对象。
  • 池容量限制:避免内存泄漏,设置最大数量。
  • 编辑器工具:可视化查看各池状态。

7. 注意事项

  • 避免直接Destroy:始终通过ReturnObject回收。
  • 线程安全:Unity无需考虑,所有操作在主线程。
  • 空池处理:动态扩展或返回null取决于设计需求。

通过以上设计,对象池能显著提升游戏性能,尤其适用于移动端和需要高性能的场景。开发者可根据项目需求调整池策略和扩展功能。

更多教学视频

Unity3D​www.bycwedu.com/promotion_channels/2146264125

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

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

相关文章

[Spring]-组件的生命周期

组件生命周期 认识组件的声明周期 实验1 通过Bean指定组件的生命周期 package com.guigu.spring.ioc.bean;Data public class User {private String username;private String password;private Car car;Autowiredpublic void setCar(Car car) {System.out.println("自动…

【golang】网络数据包捕获库 gopacket

详解 github.com/google/gopacket/pcap 包 github.com/google/gopacket/pcap 是 Go 语言中一个强大的网络数据包捕获库&#xff0c;它是 gopacket 项目的一部分&#xff0c;提供了对 libpcap&#xff08;Linux/Unix&#xff09;和 WinPcap&#xff08;Windows&#xff09;的 G…

RBTree的模拟实现

1&#xff1a;红黑树的概念 红⿊树是⼀棵⼆叉搜索树&#xff0c;他的每个结点增加⼀个存储位来表⽰结点的颜⾊&#xff0c;可以是红⾊或者⿊⾊。通过对任何⼀条从根到叶⼦的路径上各个结点的颜⾊进⾏约束&#xff0c;红⿊树确保没有⼀条路径会⽐其他路径⻓出2倍&#xff0c;因…

React 第三十九节 React Router 中的 unstable_usePrompt Hook的详细用法及案例

React Router 中的 unstable_usePrompt 是一个用于在用户尝试离开当前页面时触发确认提示的自定义钩子&#xff0c;常用于防止用户误操作导致数据丢失&#xff08;例如未保存的表单&#xff09;。 一、unstable_usePrompt用途 防止意外离开页面&#xff1a;当用户在当前页面有…

OSI 7层模型

OSI 7层模型&#xff1a; 1、物理层&#xff08;光纤等把电脑连接起来的物理手段&#xff09; 2、数据链路层&#xff08;以太网&#xff0c;确认0和1电信号的分组方式&#xff0c;负责MAC地址&#xff0c;MAC地址用于在网络中唯一标示一个网卡&#xff0c;相当于网卡的身份证…

视频编解码学习十一之视频原始数据

一、视频未编码前的原始数据是怎样的&#xff1f; 视频在未编码前的原始数据被称为 原始视频数据&#xff08;Raw Video Data&#xff09;&#xff0c;主要是按照帧&#xff08;Frame&#xff09;来组织的图像序列。每一帧本质上就是一张图片&#xff0c;通常采用某种颜色格式…

Redis学习打卡-Day1-SpringDataRedis、有状态无状态

Redis的Java客户端 Jedis 以 Redis 命令作为方法名称&#xff0c;学习成本低&#xff0c;简单实用。Jedis 是线程不安全的&#xff0c;并且频繁的创建和销毁连接会有性能损耗&#xff0c;因此推荐使用 Jedis 连接池代替Jedis的直连方式。 lettuce Lettuce是基于Netty实现的&am…

告别静态配置!Spring Boo动态线程池实战指南:Nacos+Prometheus全链路监控

一、引言 1.1 动态线程池的必要性 传统线程池的参数&#xff08;如核心线程数、队列容量&#xff09;通常通过配置文件静态定义&#xff0c;无法根据业务负载动态调整。例如&#xff0c;在电商大促场景中&#xff0c;流量可能瞬间激增&#xff0c;静态线程池容易因配置不合理导…

Flask如何读取配置信息

目录 一、使用 app.config 读取配置 二、设置配置的几种方式 1. 直接设置 2. 从 Python 文件加载 3. 从环境变量加载 4. 从字典加载 5. 从 .env 文件加载&#xff08;推荐开发环境用&#xff09; 三、读取配置值 四、最佳实践建议 在 Flask 中读取配置信息有几种常见方…

【React中useCallback钩子详解】

useCallback 是 React 中的一个性能优化 Hook,用于缓存函数引用,避免在组件重新渲染时重复创建相同的函数,从而减少不必要的子组件渲染或副作用执行。以下是其核心要点: 1. 核心作用 函数记忆化:返回一个记忆化的回调函数,仅在依赖项变化时重新创建函数,否则复用之前的函…

【!!!!终极 Java 中间件实战课:从 0 到 1 构建亿级流量电商系统全链路解决方案!!!!保姆级教程---超细】

终极 Java 中间件实战课:电商系统架构实战教程 电商系统架构实战教程1. 系统架构设计1.1 系统模块划分1.2 技术选型2. 环境搭建2.1 开发环境准备2.2 基础设施部署3. 用户服务开发3.1 创建Maven项目3.2 创建用户服务模块3.3 配置文件3.4 实体类与数据库设计3.5 DAO层实现3.6 Se…

C#异步Task,await,async和Unity同步协程

标题 TaskawaitasyncUnity协程 Task Task是声明异步任务的必要关键字&#xff0c;也可以使用Task<>泛型来定义Task的返回值。 await await是用于等待一个Task结束&#xff0c;否则让出该线程控制权&#xff0c;让步给其他线程&#xff0c;直到该Task结束才往下运行。 …

【USRP】在linux下安装python API调用

UHD 源码安装 安装库 sudo apt-get install autoconf automake build-essential ccache cmake cpufrequtils doxygen ethtool \ g git inetutils-tools libboost-all-dev libncurses5 libncurses5-dev libusb-1.0-0 libusb-1.0-0-dev \ libusb-dev python3-dev python3-mako …

什么是 NoSQL 数据库?它与关系型数据库 (RDBMS) 的主要区别是什么?

我们来详细分析一下 NoSQL 数据库与关系型数据库 (RDBMS) 的主要区别。 什么是 NoSQL 数据库&#xff1f; NoSQL (通常指 “Not Only SQL” 而不仅仅是 “No SQL”) 是一类数据库管理系统的总称。它们的设计目标是解决传统关系型数据库 (RDBMS) 在某些场景下的局限性&#xf…

蓝桥杯题库经典题型

1、数列排序&#xff08;数组 排序&#xff09; 问题描述 给定一个长度为n的数列&#xff0c;将这个数列按从小到大的顺序排列。1<n<200 输入格式 第一行为一个整数n。 第二行包含n个整数&#xff0c;为待排序的数&#xff0c;每个整数的绝对值小于10000。 输出格式 输出…

wordpress自学笔记 第三节 独立站产品和类目的三种展示方式

wordpress自学笔记 摘自 超详细WordPress搭建独立站商城教程-第三节 独立站产品和类目的三种展示方式&#xff0c;2025 WordPress搭建独立站教程#WordPress建站教程https://www.bilibili.com/video/BV1rwcteuETZ?spm_id_from333.788.videopod.sections&vd_sourcea0af3b…

智能手表蓝牙 GATT 通讯协议文档

以下是一份适用于智能手表的 蓝牙 GATT 通讯协议文档&#xff0c;适用于 BLE 5.0 及以上标准&#xff0c;兼容 iOS / Android 平台&#xff1a; 智能手表蓝牙 GATT 通讯协议文档 文档版本&#xff1a;V1.0 编写日期&#xff1a;2025年xx月xx日 产品型号&#xff1a;Aurora Wat…

Linux PCI 驱动开发指南

注&#xff1a;本文为 “Linux PCI Drivers” 相关文章合辑。 英文引文&#xff0c;机翻未校。 中文引文&#xff0c;略作重排。 如有内容异常&#xff0c;请看原文。 How To Write Linux PCI Drivers 翻译: 司延腾 Yanteng Si siyantengloongson.cn 1. 如何写 Linux PCI 驱动 …

Python 接入DeepSeek

不知不觉DeepSeek已经火了半年左右&#xff0c;冲浪都赶不上时代了。 今天开始学习。 本文旨在使用Python调用DeepSeek的接口&#xff08; 这里写目录标题 一、环境准备1.1 DeepSeek1.2 Python 二、接入DeepSeek2.1 参数2.2 requests2.3 openai2.4 返回示例 一、环境准备 1.1…

Java 集合与 MyBatis 动态 SQL 实战教程

一、Java 集合的创建与用法 在 Java 中&#xff0c;List、HashSet 和数组是常用的集合类型&#xff0c;以下是它们的创建与基本操作&#xff1a; 1. List 列表 创建方式&#xff1a; List<Integer> list new ArrayList<>(Arrays.asList(1, 2, 3)); // 可变列…