对象池是什么?
一句话:提前创建一批对象,放在“池子”里。需要用的时候拿出来,不用了再放回去,而不是反复 new 和 Destroy
在游戏中为什么常用
在游戏中,有很多对象需要频繁的创建和销毁,比如:子弹、特效、飘字、掉落物等
如果一直:
1 | Instantiate(bulletPrefab); |
短时间内大量执行,就会带来以下问题:
- 性能开销:Instantiate 和 Destroy 都不便宜,特别是对象很多的时候
- 垃圾回收GC:C# 会回收不用的内存。频繁创建销毁对象,容易产生很多垃圾,GC 一触发就可能卡一下
- 游戏卡顿:尤其是弹幕、射击、特效爆发时,最容易出现掉帧
所以对象池就是为了:减少反复创建/销毁,提高性能,减少卡顿。
简单理解方式
不用对象池:
开枪一次:
- Instantiate 一个子弹
- 子弹飞出去
- 撞到东西后Destroy
用对象池:
游戏开始时:
- 先创建50个子弹
- 隐藏起来
开枪时:
- 从池里找一个没用的子弹
- 激活,并放到枪口位置
- 发射
子弹用完后:
- 不销毁
- 隐藏并标记“可复用”
简单示例
一个基础的对象池
BulletPool.cs
1 | using System.Collections.Generic; |
发射时使用:
1 | using UnityEngine; |
归还子弹:
1 | using UnityEngine; |
其余小点
对象池最大的问题不是“拿出来”,而是“复位”
比如上一个对象可能有:
- 位置
- 旋转
- 速度
- 血量
- 动画
等等
如果不重置,就可能导致奇怪的bug:
- 子弹一生成就乱飞
- 敌人复活后血量还是上次剩下的
- 特效拖尾残留
小结
本质上是空间换时间,使用额外的内存,换运行时的流畅
很适合:
- 高频生成/销毁的对象
- 数量多的对象
- 生命周期短的对象
典型例子:
- 子弹
- 特效
- 敌人刷怪
- 飘字
- 掉落金币
- UI 消息条
不一定需要:
- 场景里只创建一次的大物体
- 很少生成的 Boss
- 几乎不会销毁的系统对象
对象池不是所有东西都要上,重点是高频复用。