--- title: Godot 节点池系统 description: Godot 节点池系统提供了高性能的节点复用机制,减少频繁创建和销毁节点带来的性能开销。 --- # Godot 节点池系统 ## 概述 Godot 节点池系统是 GFramework.Godot 中用于管理和复用 Godot 节点的高性能组件。通过对象池模式,它可以显著减少频繁创建和销毁节点带来的性能开销,特别适用于需要大量动态生成节点的场景,如子弹、特效、敌人等。 节点池系统基于 GFramework 核心的对象池系统,专门针对 Godot 节点进行了优化,提供了完整的生命周期管理和统计功能。 **主要特性**: - 节点复用机制,减少 GC 压力 - 自动生命周期管理 - 池容量限制和预热功能 - 详细的统计信息 - 类型安全的泛型设计 - 与 Godot PackedScene 无缝集成 **性能优势**: - 减少内存分配和垃圾回收 - 降低节点实例化开销 - 提高游戏运行时性能 - 优化大量对象场景的帧率 ## 核心概念 ### 节点池 节点池是一个存储可复用节点的容器。当需要节点时从池中获取,使用完毕后归还到池中,而不是销毁。这种复用机制可以显著提升性能。 ### 可池化节点 实现 `IPoolableNode` 接口的节点可以被对象池管理。接口定义了节点在池中的生命周期回调: ```csharp public interface IPoolableNode : IPoolableObject { // 从池中获取时调用 void OnAcquire(); // 归还到池中时调用 void OnRelease(); // 池被销毁时调用 void OnPoolDestroy(); // 转换为 Node 类型 Node AsNode(); } ``` ### 节点复用 节点复用是指重复使用已创建的节点实例,而不是每次都创建新实例。这可以: - 减少内存分配 - 降低 GC 压力 - 提高实例化速度 - 优化运行时性能 ## 基本用法 ### 创建可池化节点 ```csharp using Godot; using GFramework.Godot.Pool; public partial class Bullet : Node2D, IPoolableNode { private Vector2 _velocity; private float _lifetime; public void OnAcquire() { // 从池中获取时重置状态 _lifetime = 5.0f; Show(); SetProcess(true); } public void OnRelease() { // 归还到池中时清理状态 Hide(); SetProcess(false); _velocity = Vector2.Zero; } public void OnPoolDestroy() { // 池被销毁时的清理工作 QueueFree(); } public Node AsNode() { return this; } public void Initialize(Vector2 position, Vector2 velocity) { Position = position; _velocity = velocity; } public override void _Process(double delta) { Position += _velocity * (float)delta; _lifetime -= (float)delta; if (_lifetime <= 0) { // 归还到池中 ReturnToPool(); } } private void ReturnToPool() { // 通过池系统归还 var poolSystem = this.GetSystem(); poolSystem.Release("Bullet", this); } } ``` ### 创建节点池系统 ```csharp using Godot; using GFramework.Godot.Pool; public class BulletPoolSystem : AbstractNodePoolSystem { protected override PackedScene LoadScene(string key) { // 根据键加载对应的场景 return key switch { "Bullet" => GD.Load("res://prefabs/Bullet.tscn"), "EnemyBullet" => GD.Load("res://prefabs/EnemyBullet.tscn"), _ => throw new ArgumentException($"Unknown bullet type: {key}") }; } protected override void OnInit() { // 预热池,提前创建一些对象 Prewarm("Bullet", 50); Prewarm("EnemyBullet", 30); // 设置最大容量 SetMaxCapacity("Bullet", 100); SetMaxCapacity("EnemyBullet", 50); } } ``` ### 注册节点池系统 ```csharp using GFramework.Godot.Architecture; public class GameArchitecture : AbstractArchitecture { protected override void InstallModules() { // 注册节点池系统 RegisterSystem(new BulletPoolSystem()); RegisterSystem(new EffectPoolSystem()); } } ``` ### 使用节点池 ```csharp using Godot; using GFramework.Godot.Extensions; public partial class Player : Node2D { private BulletPoolSystem _bulletPool; public override void _Ready() { _bulletPool = this.GetSystem(); } public void Shoot() { // 从池中获取子弹 var bullet = _bulletPool.Acquire("Bullet"); // 初始化子弹 bullet.Initialize(GlobalPosition, Vector2.Right.Rotated(Rotation) * 500); // 添加到场景树 GetParent().AddChild(bullet.AsNode()); } } ``` ## 高级用法 ### 多类型节点池 ```csharp public class EffectPoolSystem : AbstractNodePoolSystem { protected override PackedScene LoadScene(string key) { return key switch { "Explosion" => GD.Load("res://effects/Explosion.tscn"), "Hit" => GD.Load("res://effects/Hit.tscn"), "Smoke" => GD.Load("res://effects/Smoke.tscn"), "Spark" => GD.Load("res://effects/Spark.tscn"), _ => throw new ArgumentException($"Unknown effect type: {key}") }; } protected override void OnInit() { // 为不同类型的特效设置不同的池配置 Prewarm("Explosion", 10); SetMaxCapacity("Explosion", 20); Prewarm("Hit", 20); SetMaxCapacity("Hit", 50); Prewarm("Smoke", 15); SetMaxCapacity("Smoke", 30); } } // 使用特效池 public partial class Enemy : Node2D { public void Die() { var effectPool = this.GetSystem(); var explosion = effectPool.Acquire("Explosion"); explosion.AsNode().GlobalPosition = GlobalPosition; GetParent().AddChild(explosion.AsNode()); QueueFree(); } } ``` ### 自动归还的节点 ```csharp public partial class PoolableEffect : Node2D, IPoolableNode { private AnimationPlayer _animationPlayer; private EffectPoolSystem _poolSystem; private string _effectKey; public override void _Ready() { _animationPlayer = GetNode("AnimationPlayer"); _poolSystem = this.GetSystem(); // 动画播放完毕后自动归还 _animationPlayer.AnimationFinished += OnAnimationFinished; } public void OnAcquire() { Show(); _animationPlayer.Play("default"); } public void OnRelease() { Hide(); _animationPlayer.Stop(); } public void OnPoolDestroy() { _animationPlayer.AnimationFinished -= OnAnimationFinished; QueueFree(); } public Node AsNode() => this; public void SetEffectKey(string key) { _effectKey = key; } private void OnAnimationFinished(StringName animName) { // 动画播放完毕,自动归还到池中 _poolSystem.Release(_effectKey, this); } } ``` ### 池容量管理 ```csharp public class DynamicPoolSystem : AbstractNodePoolSystem { protected override PackedScene LoadScene(string key) { return GD.Load($"res://enemies/{key}.tscn"); } protected override void OnInit() { // 初始配置 SetMaxCapacity("Slime", 50); SetMaxCapacity("Goblin", 30); SetMaxCapacity("Boss", 5); } // 动态调整池容量 public void AdjustPoolCapacity(string key, int newCapacity) { var currentSize = GetPoolSize(key); var activeCount = GetActiveCount(key); GD.Print($"池 '{key}' 当前状态:"); GD.Print($" 可用: {currentSize}"); GD.Print($" 活跃: {activeCount}"); GD.Print($" 新容量: {newCapacity}"); SetMaxCapacity(key, newCapacity); } // 根据游戏阶段预热 public void PrewarmForStage(int stage) { switch (stage) { case 1: Prewarm("Slime", 20); break; case 2: Prewarm("Slime", 30); Prewarm("Goblin", 15); break; case 3: Prewarm("Goblin", 25); Prewarm("Boss", 2); break; } } } ``` ### 池统计和监控 ```csharp public partial class PoolMonitor : Control { private BulletPoolSystem _bulletPool; private Label _statsLabel; public override void _Ready() { _bulletPool = this.GetSystem(); _statsLabel = GetNode