在游戏开发中,对象池技术通过复用已创建对象,显著降低高频创建/销毁操作带来的性能损耗。无论是Unity还是Godot,在以下场景都需对象池:
using Godot;
using System.Collections.Generic;
public partial class ObjectPool : Node
{
private static ObjectPool _instance;
public static ObjectPool Instance => _instance;
private Dictionary> _pools = new Dictionary>();
private Dictionary _prefabs = new Dictionary();
[Export] PackedScene bulletPrefab;
public override void _Ready()
{
_instance = this; // Godot单例需通过Autoload加载
InitializePool("Bullet", bulletPrefab, 40);
}
// 初始化对象池
public void InitializePool(string poolKey, PackedScene prefab, int initialSize)
{
if (!_pools.ContainsKey(poolKey))
{
var queue = new Queue();
for (int i = 0; i < initialSize; i++)
{
Node obj = prefab.Instantiate();
obj.ProcessMode = Node.ProcessModeEnum.Disabled; // 禁用节点逻辑
queue.Enqueue(obj);
}
_pools.Add(poolKey, queue);
_prefabs.Add(poolKey, prefab);
}
}
// 获取对象
public Node Spawn(string poolKey)
{
if (_pools.TryGetValue(poolKey, out Queue pool))
{
Node3D obj = (Node3D)(pool.Count > 0 ? pool.Dequeue() : CreateNewObject(poolKey));
obj.ProcessMode = Node.ProcessModeEnum.Inherit; // 启用节点逻辑
// obj.PhysicsInterpolationMode = PhysicsInterpolationModeEnum.Inherit;
return obj;
}
GD.PrintErr($"Pool {poolKey} not initialized!");
return null;
}
// 回收对象
public void Despawn(string poolKey, Node obj)
{
if (_pools.ContainsKey(poolKey))
{
obj.ProcessMode = Node.ProcessModeEnum.Disabled;
// obj.PhysicsInterpolationMode = PhysicsInterpolationModeEnum.Off;
_pools[poolKey].Enqueue(obj);
}
}
private Node CreateNewObject(string poolKey)
{
if (_prefabs.TryGetValue(poolKey, out PackedScene prefab))
{
return prefab.Instantiate();
}
return null;
}
}
public partial class Bullet : RigidBody3D
{
[Export] public string PoolKey = "Bullet"; // 在Godot编辑器中指定所属对象池
public void ReturnToPool()
{
GetTree().Root.RemoveChild(this);
ObjectPool.Instance.Despawn(PoolKey, this);
}
}
public partial class ObjectPool : Node
{
[Export] PackedScene bulletPrefab;
// 游戏启动时初始化
public override void _Ready()
{
_instance = this; // Godot单例需通过Autoload加载
InitializePool("Bullet", bulletPrefab, 40);
}
}
public partial class Fight : Node
{
[Export] PackedScene bulletPack;
public override void _Ready()
{
// 当然你也可以在这里初始化
ObjectPool.Instance.InitializePool("Bullet", bulletPack, 40);
}
public void Fire()
{
// 原有的实例化方法
// Bullet bullet = bulletPack.Instantiate();
Bullet bullet = (Bullet)ObjectPool.Instance.Spawn("Bullet");
// AddChild(bullet); // 需要手动添加至场景树
GetTree().Root.AddChild(bullet);
}
}
public partial class Bullet : RigidBody3D
{
// 在PoolableObject中触发回收(如碰撞检测后)
protected virtual void OnBodyEntered(Node3D body)
{
CallDeferred("ReturnToPool");
}
}
实际应用效果测试
https://www.bilibili.com/video/BV1DnZtYLEFU/?share_source=copy_web&vd_source=c3f882a4384ffe1e99cabd9e8780b610
我对目前的对象池并不满意,正在探索其他优化更加显著的方案,一下内容全是AI生成,并无实际测试
public partial class ObjectPool : Node
{
// 改用Stack存储可用对象
private Dictionary> _pools = new Dictionary>();
private Dictionary _prefabs = new Dictionary>();
private Dictionary> _activeObjects = new Dictionary>();
public void InitializePool(string poolKey, PackedScene prefab, int initialSize)
{
if (!_pools.ContainsKey(poolKey))
{
var stack = new Stack(initialSize); // 预分配容量
for (int i = 0; i < initialSize; i++)
{
Node obj = prefab.Instantiate();
obj.ProcessMode = Node.ProcessModeEnum.Disabled;
stack.Push(obj);
}
_pools.Add(poolKey, stack);
_prefabs.Add(poolKey, prefab);
_activeObjects.Add(poolKey, new List());
}
}
public Node Spawn(string poolKey, Vector2 position)
{
if (_pools.TryGetValue(poolKey, out Stack pool))
{
Node obj = pool.Count > 0 ? pool.Pop() : CreateNewObject(poolKey);
// 自动添加至场景树
if (obj.GetParent() == null)
AddChild(obj);
else
obj.GetParent().MoveChild(obj, -1); // 提升渲染优先级
obj.Position = position;
obj.ProcessMode = Node.ProcessModeEnum.Inherit;
_activeObjects[poolKey].Add(obj);
return obj;
}
GD.PrintErr($"Pool {poolKey} not initialized!");
return null;
}
public void Despawn(string poolKey, Node obj)
{
if (_pools.ContainsKey(poolKey))
{
obj.ProcessMode = Node.ProcessModeEnum.Disabled;
_pools[poolKey].Push(obj);
_activeObjects[poolKey].Remove(obj);
// 优化内存:当空闲对象超过上限时自动释放
if (_pools[poolKey].Count > _prefabs[poolKey].GetMeta("MaxPoolSize", 50))
{
Node excessObj = _pools[poolKey].Pop();
excessObj.QueueFree();
}
}
}
}
public class AdvancedObjectPool
{
// 分代管理 + 索引查找
private struct PoolSegment
{
public Stack HotBuffer; // 高频区(L1缓存友好)
public Queue WarmQueue; // 中频区
public List ColdStorage; // 低频区(可能被GC)
}
private Dictionary _pools = new();
private Dictionary _objectMap = new();
}
public class MemoryPool where T : Node, new()
{
private T[] _memoryBlock; // 连续内存块
private int[] _freeIndexes; // 空闲索引栈
private int _pointer;
public void Initialize(int capacity)
{
_memoryBlock = new T[capacity];
_freeIndexes = new int[capacity];
// 预分配内存并初始化
for (int i = 0; i < capacity; i++)
{
_memoryBlock[i] = new T();
_freeIndexes[i] = i;
}
_pointer = capacity - 1;
}
public T Spawn()
{
if (_pointer >= 0)
{
int index = _freeIndexes[_pointer--];
return _memoryBlock[index];
}
// 动态扩容策略
return ExpandPool().Spawn();
}
}
public class ChunkedPool
{
private List _chunks = new(); // 内存块集合
private Stack _freeSlots = new(); // 全局空闲槽位
public Node Spawn()
{
if (_freeSlots.Count == 0)
{
AddNewChunk();
}
int index = _freeSlots.Pop();
(int chunkIdx, int slotIdx) = DecodeIndex(index);
return _chunks[chunkIdx][slotIdx];
}
private void AddNewChunk()
{
Node[] chunk = new Node[256]; // 每块256对象
for (int i = 0; i < 256; i++)
{
chunk[i] = CreateObject();
_freeSlots.Push(EncodeIndex(_chunks.Count, i));
}
_chunks.Add(chunk);
}
}