第6章 组件与组合
组件化架构是现代游戏开发的核心设计模式之一。本章将介绍如何在 Godot C# 中构建灵活的组件系统,包括传统组件模式、轻量级 ECS 架构以及依赖注入容器的实现。
1. 设计原理与思路
1.1 组合优于继承的设计哲学
传统的面向对象编程倾向于使用继承来复用代码,但在游戏开发中,继承往往会导致以下问题:
继承的困境:
// 继承导致的类爆炸
public class Character : Node { }
public class Player : Character { }
// 玩家可以飞行
public class FlyingPlayer : Player { }
// 玩家可以隐身
public class InvisiblePlayer : Player { }
// 玩家既可以飞行又可以隐身?
// public class FlyingInvisiblePlayer : ??? // 多重继承问题
组合的解决方案:
// 组件化设计
public class Player : Node
{
// 通过组合实现功能
public MovementComponent Movement { get; private set; }
public HealthComponent Health { get; private set; }
public override void _Ready()
{
Movement = AddComponent<MovementComponent>();
Health = AddComponent<HealthComponent>();
// 动态添加能力
if (CanFly)
AddComponent<FlyingComponent>();
if (CanBecomeInvisible)
AddComponent<InvisibilityComponent>();
}
}
组合的优势:
继承 vs 组合:
继承(Is-A关系):
Character
│
┌─────────────┼─────────────┐
│ │ │
Player Enemy NPC
│
┌────┴────┐
│ │
FlyingPlayer InvisiblePlayer
│
│ 问题:无法同时拥有飞行和隐身
▼
FlyingInvisiblePlayer
组合(Has-A关系):
Entity
│
├── MovementComponent
├── HealthComponent
├── FlyingComponent (可选)
├── InvisibilityComponent (可选)
└── WeaponComponent (可选)
优势:可以自由组合任意功能
1.2 ECS架构的演进
ECS(Entity-Component-System)架构经历了三个主要阶段:
第一代:面向对象的组件模式(OOP Components)
- 组件是行为容器
- 组件可以包含逻辑
- 典型的代表:Unity的MonoBehaviour
第二代:数据驱动的组件模式(Data-Oriented Components)
- 组件是纯数据结构
- 逻辑由System处理
- 更好的缓存友好性
第三代:ECS(Entity-Component-System)
- 实体只是ID
- 组件是数据
- 系统是逻辑处理器
- 扁平化的内存布局
内存布局对比:
面向对象(OOP):
[Entity1: Transform, Health, Renderer]
[Entity2: Transform, Health]
[Entity3: Renderer]
问题:内存分散,缓存未命中率高
ECS(Data-Oriented):
Transforms: [T1][T2][T3][T4]...
Healths: [H1][H2][H3][H4]...
Renderers: [R1][R2][R3][R4]...
优势:连续内存访问,CPU缓存友好
为什么这样设计?
- 缓存友好:连续存储相同类型的数据,提高CPU缓存命中率
- 并行友好:System可以并行处理大量实体
- 查询高效:可以快速筛选拥有特定组件组合的实体
1.3 组件化与Godot节点系统的结合
Godot的节点系统本质上就是组件化架构。我们的组件系统建立在Godot节点系统之上:
架构层次:
Level 1 - Godot引擎:
├─ Node
├─ Node2D
├─ Node3D
└─ Control
Level 2 - 框架组件层:
├─ ComponentBase : Node
├─ GameEntity : ComponentBase
└─ UIComponent : Control
Level 3 - 业务组件层:
├─ HealthComponent : ComponentBase
├─ MovementComponent : ComponentBase
├─ WeaponComponent : ComponentBase
└─ InventoryComponent : ComponentBase
Level 4 - 具体游戏逻辑:
├─ PlayerHealth : HealthComponent
├─ EnemyAI : AIComponent
└─ BossAttack : AttackComponent
这种设计的好处:
- 保留Godot编辑器的可视化编辑能力
- 利用Godot的信号系统
- 与Godot的生命周期(_Ready, _Process等)无缝集成
2. 使用场景分析
2.1 适用场景
复杂实体:角色需要同时具备多种能力
// RPG角色系统
public class RPGCharacter : GameEntity
{
protected override void SetupComponents()
{
AddComponent<HealthComponent>(new HealthComponent
{
MaxHealth = 100,
HealthRegenRate = 1.0f
});
AddComponent<MovementComponent>(new MovementComponent
{
MoveSpeed = 5.0f,
CanSprint = true
});
AddComponent<CombatComponent>(new CombatComponent
{
AttackDamage = 10,
AttackSpeed = 1.0f
});
AddComponent<InventoryComponent>(new InventoryComponent
{
MaxSlots = 20
});
AddComponent<EquipmentComponent>(); // 装备系统
AddComponent<SkillComponent>(); // 技能系统
}
}
可复用功能:多个实体共享相同的行为
// 多个实体都可以拥有生命值
public class Player : GameEntity { }
public class Enemy : GameEntity { }
public class DestructibleObject : GameEntity { }
// 所有都可以添加HealthComponent
player.AddComponent<HealthComponent>();
enemy.AddComponent<HealthComponent>();
object.AddComponent<HealthComponent>();
2.2 不适用场景
简单对象:只有一个功能的简单对象
// 不需要组件化
public class SimpleBullet : Node2D
{
[Export] public float Speed { get; set; } = 500f;
[Export] public int Damage { get; set; } = 10;
public override void _PhysicsProcess(double delta)
{
Position += Transform.X * Speed * (float)delta;
}
}
// 对比:组件化(过度设计)
public class BulletEntity : GameEntity
{
protected override void SetupComponents()
{
AddComponent<MovementComponent>();
AddComponent<DamageComponent>();
// 太多样板代码
}
}
紧密耦合的逻辑:逻辑高度依赖,无法拆分的功能
2.3 典型案例
RPG角色系统:生命、魔法、经验、装备、技能等模块独立 装备系统:武器、护甲、饰品可以任意组合 Buff/Debuff系统:通过添加/移除组件实现临时效果
装备系统组件图:
角色实体:
├─ HealthComponent
├─ ManaComponent
├─ MovementComponent
├─ CombatComponent
├─ InventoryComponent
│ ├─ Slot0: Sword (WeaponComponent)
│ ├─ Slot1: Shield (ArmorComponent)
│ └─ Slot2: Potion (ConsumableComponent)
├─ EquipmentComponent
│ ├─ Weapon: Sword
│ ├─ Armor: PlateMail
│ └─ Ring: RingOfHealth
└─ BuffComponent
├─ SpeedBuff (持续时间30秒)
└─ StrengthBuff (持续时间60秒)
优势:装备更换只需替换组件引用
3. 实现细节讲解
3.1 依赖注入容器的工作原理
依赖注入容器管理对象的创建和依赖关系:
DI容器工作流程:
1. 注册阶段(Register):
container.Register<IService, ServiceImpl>(ServiceLifetime.Singleton);
2. 解析阶段(Resolve):
var service = container.Resolve<IService>();
3. 创建实例(Create Instance):
├─ 检查构造函数
├─ 解析参数依赖
├─ 创建实例
├─ 属性注入
└─ 调用[Initialize]方法
4. 生命周期管理:
Singleton: 全局唯一实例
Scoped: 作用域内共享
Transient: 每次新建实例
构造函数注入的实现:
private object CreateInstance(Type implementationType)
{
// 1. 获取构造函数
var constructor = implementationType.GetConstructors()
.OrderByDescending(c => c.GetParameters().Length)
.First();
var parameters = constructor.GetParameters();
var args = new object[parameters.Length];
// 2. 解析每个参数
for (int i = 0; i < parameters.Length; i++)
{
var param = parameters[i];
// 递归解析依赖
args[i] = Resolve(param.ParameterType);
}
// 3. 创建实例
var instance = constructor.Invoke(args);
// 4. 执行属性注入
InjectProperties(instance);
return instance;
}
// 为什么这样设计?
// 递归解析确保所有依赖都被满足
// 支持嵌套依赖(A依赖B,B依赖C)
3.2 组件生命周期管理
组件的生命周期与Godot节点生命周期结合:
public abstract class ComponentBase : Node
{
// Godot生命周期
public override void _Ready()
{
base._Ready();
Initialize(); // 调用框架初始化
}
public override void _Process(double delta)
{
if (_isEnabled && _isInitialized)
{
OnUpdate((float)delta);
}
}
public override void _ExitTree()
{
OnDestroy();
base._ExitTree();
}
// 框架生命周期
protected virtual void Initialize()
{
if (_isInitialized) return;
OnInitialize(); // 子类实现
_isInitialized = true;
}
protected abstract void OnInitialize();
protected virtual void OnUpdate(float deltaTime) { }
protected virtual void OnDestroy() { }
}
生命周期执行顺序:
1. _Ready() [Godot]
└─ Initialize() [框架]
└─ OnInitialize() [子类]
2. _Process() [Godot] - 每帧
└─ OnUpdate() [子类] - 如果启用
3. _ExitTree() [Godot]
└─ OnDestroy() [子类]
注意:OnInitialize在_Godot的_Ready之后执行,确保节点树已准备好
3.3 与Godot原生组件的协作
我们的组件系统与Godot原生节点和组件协作:
public class HealthComponent : ComponentBase
{
// 引用Godot原生节点
private ProgressBar _healthBar;
private AnimationPlayer _animator;
protected override void OnInitialize()
{
// 在节点树中查找Godot节点
_healthBar = GetNode<ProgressBar>("UI/HealthBar");
_animator = GetNode<AnimationPlayer>("AnimationPlayer");
// 连接Godot信号
_healthBar.ValueChanged += OnHealthBarValueChanged;
}
// 与Godot信号集成
[Signal]
public delegate void HealthDepletedEventHandler();
public void TakeDamage(int damage)
{
CurrentHealth -= damage;
// 触发Godot信号
EmitSignal(SignalName.HealthDepleted);
// 播放Godot动画
_animator?.Play("hit");
}
}
// 组合使用示例
public class Player : CharacterBody2D // Godot原生
{
private HealthComponent _health; // 框架组件
public override void _Ready()
{
// 添加框架组件
_health = new HealthComponent();
AddChild(_health);
// 连接框架组件信号
_health.HealthDepleted += OnHealthDepleted;
}
private void OnHealthDepleted()
{
// 使用Godot功能
GetTree().ReloadCurrentScene();
}
}
为什么这样设计?
- 利用Godot的场景系统和可视化编辑器
- 保留Godot信号系统的便利性
- 渐进式采用框架组件,不完全替换Godot功能
4. 性能与权衡
4.1 组件查找的开销
组件查找主要有两种方式,各有优劣:
方式一:字典查找(O(1))
// Entity中使用字典存储组件
private Dictionary<Type, IComponent> _components = new();
public T GetComponent<T>() where T : class, IComponent
{
if (_components.TryGetValue(typeof(T), out var component))
return component as T;
return null;
}
// 时间复杂度:O(1)
// 内存开销:每个组件类型一个字典项
方式二:线性查找(O(n))
// Godot的GetNode方式
public T GetComponent<T>()
{
foreach (Node child in GetChildren())
{
if (child is T component)
return component;
}
return null;
}
// 时间复杂度:O(n),n为子节点数量
// 内存开销:无额外开销
性能对比:
| 查找方式 | 时间复杂度 | 内存开销 | 适用场景 |
|---|---|---|---|
| 字典查找 | O(1) | 中等 | 频繁查找 |
| 线性查找 | O(n) | 低 | 不频繁查找 |
| 缓存引用 | O(1) | 高 | 最高频访问 |
优化策略:
// 缓存高频访问的组件
public class Player : GameEntity
{
private HealthComponent _health; // 缓存
protected override void OnInitialize()
{
_health = GetComponent<HealthComponent>(); // 初始化时缓存
}
public void TakeDamage(int damage)
{
_health.TakeDamage(damage); // 直接使用缓存,O(1)
}
}
4.2 内存布局优化
ECS架构的核心优势之一是内存布局优化:
传统OOP组件内存布局:
Entity1: [Transform][Health][Renderer]
Entity2: [Transform][Health]
Entity3: [Renderer][Transform]
访问所有Transform时的内存访问模式:
读取Entity1.Transform (缓存行1)
读取Entity2.Transform (缓存行2)
读取Entity3.Transform (缓存行3)
→ 缓存未命中率高
ECS内存布局:
Transforms: [T1][T2][T3][T4][T5][T6][T7][T8]...
Healths: [H1][H2][H3][H4][H5][H6][H7][H8]...
Renderers: [R1][R2][R3][R4][R5][R6][R7][R8]...
访问所有Transform时的内存访问模式:
读取T1, T2, T3, T4... (都在连续的缓存行)
→ 缓存命中率高
缓存友好的代码:
// ECS System:连续处理相同类型的数据
public class MovementSystem : SystemBase<TransformComponent, MovementComponent>
{
public override void Execute(float deltaTime)
{
// 遍历连续的Transform数据
foreach (var entity in _entities)
{
var transform = GetC1(entity);
var movement = GetC2(entity);
// 连续的内存访问模式
transform.Position += movement.Velocity * deltaTime;
}
}
}
4.3 与继承的性能对比
| 特性 | 继承 | 组件化(ECS) |
|---|---|---|
| 实例创建 | 快 | 中等(需要组装) |
| 方法调用 | 快(虚函数) | 快(直接调用) |
| 内存布局 | 分散 | 连续(ECS) |
| 运行时组合 | 不支持 | 支持 |
| 缓存友好性 | 低 | 高(ECS) |
| 代码复用 | 继承链 | 组件组合 |
实际性能考量:
在Godot C#环境中,对于中小型项目(<1000个实体),性能差异通常可以忽略。选择架构时应更多考虑可维护性。
性能影响实际案例:
场景:100个敌人,每个有5个组件
继承方案:
- 内存占用:~500KB
- 更新耗时:0.5ms
ECS方案:
- 内存占用:~400KB(更紧凑)
- 更新耗时:0.3ms(缓存友好)
差异:在60FPS下,0.2ms的差异可以忽略不计
→ 选择更易于维护的方案
5. 实战指南
5.1 组件设计的步骤
步骤1:识别实体和职责
// 列出游戏中的实体
public enum EntityType
{
Player, // 玩家角色
Enemy, // 敌人
NPC, // NPC
Item, // 物品
Projectile // 投射物
}
// 列出每个实体的职责
// Player: 移动、战斗、背包、装备、技能
// Enemy: 移动、战斗、AI
// Item: 可被拾取、可使用
步骤2:设计组件接口
// 定义组件接口
public interface IDamageable
{
void TakeDamage(int damage, Node source);
bool IsDead { get; }
}
public interface IInteractable
{
void Interact(Node interactor);
string InteractionPrompt { get; }
}
public interface ICollectible
{
void Collect(Node collector);
string ItemId { get; }
}
步骤3:实现基础组件
// 实现可复用的基础组件
public class HealthComponent : ComponentBase, IDamageable
{
[Export] public int MaxHealth { get; set; } = 100;
public int CurrentHealth { get; private set; }
protected override void OnInitialize()
{
CurrentHealth = MaxHealth;
}
public void TakeDamage(int damage, Node source)
{
CurrentHealth -= damage;
if (CurrentHealth <= 0)
{
Die();
}
}
private void Die()
{
EmitSignal(SignalName.Died);
// 通知其他系统
MessageBus.Instance.Publish(new EntityDiedMessage { Entity = this });
}
}
步骤4:组装实体
// 创建具体的实体类
public class Enemy : GameEntity
{
protected override void SetupComponents()
{
AddComponent<HealthComponent>(new HealthComponent
{
MaxHealth = 50
});
AddComponent<MovementComponent>();
AddComponent<AIComponent>(new AIComponent
{
DetectionRange = 10f,
AttackRange = 2f
});
AddComponent<CombatComponent>(new CombatComponent
{
AttackDamage = 5,
AttackCooldown = 1.0f
});
}
}
5.2 常见错误:组件过度拆分
过度拆分的症状:
- 一个简单功能需要5个组件
- 组件之间高度依赖
- 为了修改一个行为需要修改多个组件
// 过度拆分的例子
public class Player : GameEntity
{
protected override void SetupComponents()
{
// 太多了!这些应该合并
AddComponent<HorizontalMovementComponent>();
AddComponent<VerticalMovementComponent>();
AddComponent<JumpComponent>();
AddComponent<WalkComponent>();
AddComponent<RunComponent>();
AddComponent<SprintComponent>();
}
}
// 更好的设计:合并相关功能
public class Player : GameEntity
{
protected override void SetupComponents()
{
AddComponent<MovementComponent>(new MovementComponent
{
WalkSpeed = 3f,
RunSpeed = 6f,
SprintSpeed = 9f,
JumpForce = 10f
});
}
}
拆分原则:
- 单一职责:一个组件只做一件事
- 高内聚:组件内部的功能紧密相关
- 低耦合:组件之间的依赖最小化
合理的组件划分:
✓ HealthComponent - 管理生命值
✓ MovementComponent - 管理移动
✓ CombatComponent - 管理战斗
✓ InventoryComponent - 管理背包
✗ MovementComponent + AnimationComponent 分开(动画应该独立)
✗ HealthComponent + DamageReductionComponent 分开(应该合并)
5.3 测试策略
单元测试组件:
[Test]
public void TestHealthComponent()
{
// Arrange
var health = new HealthComponent { MaxHealth = 100 };
health.Initialize();
// Act
health.TakeDamage(30, null);
// Assert
Assert.AreEqual(70, health.CurrentHealth);
}
[Test]
public void TestHealthComponent_Death()
{
// Arrange
var health = new HealthComponent { MaxHealth = 100 };
health.Initialize();
bool died = false;
health.Died += () => died = true;
// Act
health.TakeDamage(100, null);
// Assert
Assert.IsTrue(died);
Assert.IsTrue(health.IsDead);
}
集成测试实体组装:
[Test]
public void TestPlayerEntityAssembly()
{
// Arrange
var player = new Player();
// Act
player._Ready(); // 触发组件初始化
// Assert
Assert.IsNotNull(player.GetComponent<HealthComponent>());
Assert.IsNotNull(player.GetComponent<MovementComponent>());
Assert.IsNotNull(player.GetComponent<CombatComponent>());
}
Mock依赖:
[Test]
public void TestCombatComponent_WithMockHealth()
{
// Arrange
var mockHealth = Substitute.For<IDamageable>();
var combat = new CombatComponent();
combat.SetTarget(mockHealth);
// Act
combat.Attack();
// Assert
mockHealth.Received().TakeDamage(Arg.Any<int>(), Arg.Any<Node>());
}
性能测试:
[Test]
public void TestComponentLookupPerformance()
{
// 测试组件查找性能
var entity = new Entity();
for (int i = 0; i < 100; i++)
{
entity.AddComponent<TestComponent>();
}
var stopwatch = Stopwatch.StartNew();
for (int i = 0; i < 10000; i++)
{
var component = entity.GetComponent<TestComponent>();
}
stopwatch.Stop();
Assert.Less(stopwatch.ElapsedMilliseconds, 100); // 应该在100ms内完成
}
6. 组件化架构设计
组件化架构将游戏对象分解为可复用、可组合的独立单元,每个组件负责特定的功能模块。
6.1.1 ComponentBase 基类
首先定义所有组件的基类,提供通用的生命周期管理和事件系统。
// 文件路径: Scripts/Framework/Components/ComponentBase.cs
using Godot;
using System;
using System.Collections.Generic;
namespace GameFramework.Components
{
/// <summary>
/// 组件基类 - 所有游戏组件的抽象基类
/// 提供生命周期管理、事件通信和序列化支持
/// </summary>
public abstract class ComponentBase : Node, IDisposable
{
#region 字段
// 组件是否已初始化
private bool _isInitialized = false;
// 组件是否已启用
private bool _isEnabled = true;
// 组件优先级 - 影响更新顺序,数值越小优先级越高
private int _priority = 0;
// 组件唯一标识符
private string _componentId;
// 组件拥有的子组件列表
private readonly List<ComponentBase> _childComponents = new List<ComponentBase>();
// 组件属性字典 - 用于运行时动态属性
private readonly Dictionary<string, object> _properties = new Dictionary<string, object>();
#endregion
#region 属性
/// <summary>
/// 组件是否已初始化
/// </summary>
public bool IsInitialized => _isInitialized;
/// <summary>
/// 组件是否已启用
/// </summary>
public bool IsEnabled
{
get => _isEnabled;
set
{
if (_isEnabled != value)
{
_isEnabled = value;
OnEnabledChanged(value);
}
}
}
/// <summary>
/// 组件优先级
/// </summary>
public int Priority
{
get => _priority;
set
{
_priority = value;
// 通知父节点重新排序
EmitSignal(SignalName.PriorityChanged, value);
}
}
/// <summary>
/// 组件唯一ID
/// </summary>
public string ComponentId => _componentId;
/// <summary>
/// 父组件
/// </summary>
public ComponentBase ParentComponent => GetParent() as ComponentBase;
/// <summary>
/// 根组件
/// </summary>
public ComponentBase RootComponent
{
get
{
var current = this;
while (current.ParentComponent != null)
{
current = current.ParentComponent;
}
return current;
}
}
#endregion
#region 信号
[Signal]
public delegate void InitializedEventHandler();
[Signal]
public delegate void EnabledChangedEventHandler(bool enabled);
[Signal]
public delegate void PriorityChangedEventHandler(int priority);
[Signal]
public delegate void ComponentDestroyedEventHandler();
#endregion
#region 生命周期
/// <summary>
/// Godot 节点初始化入口
/// </summary>
public override void _Ready()
{
base._Ready();
// 生成唯一ID
_componentId = Guid.NewGuid().ToString("N");
// 设置节点名称为组件类型名(如果未设置)
if (string.IsNullOrEmpty(Name) || Name == GetType().Name)
{
Name = $"{GetType().Name}_{_componentId.Substring(0, 8)}";
}
// 执行组件初始化
Initialize();
}
/// <summary>
/// 每帧更新
/// </summary>
public override void _Process(double delta)
{
if (_isEnabled && _isInitialized)
{
OnUpdate((float)delta);
}
}
/// <summary>
/// 固定时间间隔更新
/// </summary>
public override void _PhysicsProcess(double delta)
{
if (_isEnabled && _isInitialized)
{
OnFixedUpdate((float)delta);
}
}
/// <summary>
/// 节点被销毁时调用
/// </summary>
public override void _ExitTree()
{
OnDestroy();
base._ExitTree();
}
/// <summary>
/// 组件初始化 - 子类必须实现
/// </summary>
protected virtual void Initialize()
{
if (_isInitialized) return;
// 子类在此添加初始化逻辑
OnInitialize();
_isInitialized = true;
EmitSignal(SignalName.Initialized);
GD.Print($"[ComponentBase] 组件已初始化: {GetType().Name} ({_componentId})");
}
/// <summary>
/// 子类实现的具体初始化逻辑
/// </summary>
protected abstract void OnInitialize();
/// <summary>
/// 子类实现的每帧更新逻辑
/// </summary>
protected virtual void OnUpdate(float deltaTime) { }
/// <summary>
/// 子类实现的固定更新逻辑
/// </summary>
protected virtual void OnFixedUpdate(float deltaTime) { }
/// <summary>
/// 子类实现的销毁逻辑
/// </summary>
protected virtual void OnDestroy()
{
EmitSignal(SignalName.ComponentDestroyed);
Dispose();
}
/// <summary>
/// 启用状态改变时的回调
/// </summary>
protected virtual void OnEnabledChanged(bool enabled)
{
EmitSignal(SignalName.EnabledChanged, enabled);
}
#endregion
#region 组件管理
/// <summary>
/// 添加子组件
/// </summary>
public T AddComponent<T>() where T : ComponentBase, new()
{
var component = new T();
AddChild(component);
_childComponents.Add(component);
// 按优先级排序
SortChildComponents();
return component;
}
/// <summary>
/// 获取组件
/// </summary>
public T GetComponent<T>() where T : ComponentBase
{
foreach (var child in _childComponents)
{
if (child is T t)
return t;
}
return null;
}
/// <summary>
/// 获取所有指定类型的组件
/// </summary>
public List<T> GetComponents<T>() where T : ComponentBase
{
var result = new List<T>();
foreach (var child in _childComponents)
{
if (child is T t)
result.Add(t);
}
return result;
}
/// <summary>
/// 移除组件
/// </summary>
public bool RemoveComponent<T>() where T : ComponentBase
{
var component = GetComponent<T>();
if (component != null)
{
_childComponents.Remove(component);
component.QueueFree();
return true;
}
return false;
}
/// <summary>
/// 按优先级排序子组件
/// </summary>
private void SortChildComponents()
{
_childComponents.Sort((a, b) => a._priority.CompareTo(b._priority));
}
#endregion
#region 属性系统
/// <summary>
/// 设置动态属性
/// </summary>
public void SetProperty(string key, object value)
{
_properties[key] = value;
}
/// <summary>
/// 获取动态属性
/// </summary>
public T GetProperty<T>(string key, T defaultValue = default)
{
if (_properties.TryGetValue(key, out var value) && value is T t)
{
return t;
}
return defaultValue;
}
/// <summary>
/// 检查属性是否存在
/// </summary>
public bool HasProperty(string key)
{
return _properties.ContainsKey(key);
}
/// <summary>
/// 移除属性
/// </summary>
public bool RemoveProperty(string key)
{
return _properties.Remove(key);
}
#endregion
#region IDisposable
/// <summary>
/// 释放资源
/// </summary>
public virtual void Dispose()
{
_childComponents.Clear();
_properties.Clear();
}
#endregion
}
}
6.1.2 组件生命周期
组件生命周期管理确保组件按正确顺序初始化和销毁。
// 文件路径: Scripts/Framework/Components/Lifecycle/LifecycleManager.cs
using Godot;
using System;
using System.Collections.Generic;
using System.Linq;
namespace GameFramework.Components.Lifecycle
{
/// <summary>
/// 生命周期管理器 - 管理组件的创建、初始化和销毁流程
/// </summary>
public class LifecycleManager : Node
{
#region 单例
private static LifecycleManager _instance;
public static LifecycleManager Instance
{
get
{
if (_instance == null)
{
// 尝试从场景中获取
_instance = Engine.GetSingleton(nameof(LifecycleManager)) as LifecycleManager;
// 如果不存在,创建新的实例
if (_instance == null)
{
_instance = new LifecycleManager();
Engine.RegisterSingleton(nameof(LifecycleManager), _instance);
}
}
return _instance;
}
}
#endregion
#region 字段
// 待初始化的组件队列
private readonly Queue<ComponentBase> _initializationQueue = new Queue<ComponentBase>();
// 活跃组件列表
private readonly List<ComponentBase> _activeComponents = new List<ComponentBase>();
// 待销毁组件队列
private readonly Queue<ComponentBase> _destructionQueue = new Queue<ComponentBase>();
// 是否正在处理生命周期
private bool _isProcessingLifecycle = false;
#endregion
#region 属性
/// <summary>
/// 活跃组件数量
/// </summary>
public int ActiveComponentCount => _activeComponents.Count;
#endregion
#region Godot 生命周期
public override void _Ready()
{
base._Ready();
// 设置处理模式为始终运行
ProcessMode = ProcessModeEnum.Always;
}
public override void _Process(double delta)
{
// 处理生命周期队列
ProcessLifecycleQueues();
}
#endregion
#region 生命周期管理
/// <summary>
/// 注册组件到生命周期管理器
/// </summary>
public void RegisterComponent(ComponentBase component)
{
if (component == null || component.IsInitialized)
return;
// 添加到初始化队列
_initializationQueue.Enqueue(component);
GD.Print($"[LifecycleManager] 组件已注册: {component.GetType().Name}");
}
/// <summary>
/// 注销组件
/// </summary>
public void UnregisterComponent(ComponentBase component)
{
if (component == null)
return;
// 从活跃列表移除
_activeComponents.Remove(component);
// 添加到销毁队列
_destructionQueue.Enqueue(component);
GD.Print($"[LifecycleManager] 组件已注销: {component.GetType().Name}");
}
/// <summary>
/// 处理生命周期队列
/// </summary>
private void ProcessLifecycleQueues()
{
if (_isProcessingLifecycle)
return;
_isProcessingLifecycle = true;
try
{
// 处理初始化队列
ProcessInitializationQueue();
// 处理销毁队列
ProcessDestructionQueue();
}
finally
{
_isProcessingLifecycle = false;
}
}
/// <summary>
/// 处理初始化队列
/// </summary>
private void ProcessInitializationQueue()
{
// 限制每帧初始化的组件数量,避免卡顿
const int maxInitializationsPerFrame = 10;
int initializedCount = 0;
while (_initializationQueue.Count > 0 && initializedCount < maxInitializationsPerFrame)
{
var component = _initializationQueue.Dequeue();
if (component != null && !component.IsInitialized)
{
// 添加到活跃列表
_activeComponents.Add(component);
// 按优先级排序
SortActiveComponents();
initializedCount++;
}
}
}
/// <summary>
/// 处理销毁队列
/// </summary>
private void ProcessDestructionQueue()
{
while (_destructionQueue.Count > 0)
{
var component = _destructionQueue.Dequeue();
if (component != null)
{
// 清理引用
if (!component.IsQueuedForDeletion())
{
component.QueueFree();
}
}
}
}
/// <summary>
/// 按优先级排序活跃组件
/// </summary>
private void SortActiveComponents()
{
_activeComponents.Sort((a, b) =>
{
// 使用反射获取优先级(因为 Priority 是受保护的)
int priorityA = GetComponentPriority(a);
int priorityB = GetComponentPriority(b);
return priorityA.CompareTo(priorityB);
});
}
/// <summary>
/// 获取组件优先级
/// </summary>
private int GetComponentPriority(ComponentBase component)
{
// 通过属性访问优先级
var property = component.GetType().GetProperty("Priority");
if (property != null)
{
return (int)property.GetValue(component);
}
return 0;
}
#endregion
#region 批量操作
/// <summary>
/// 启用所有组件
/// </summary>
public void EnableAllComponents()
{
foreach (var component in _activeComponents)
{
if (component != null)
{
component.IsEnabled = true;
}
}
}
/// <summary>
/// 禁用所有组件
/// </summary>
public void DisableAllComponents()
{
foreach (var component in _activeComponents)
{
if (component != null)
{
component.IsEnabled = false;
}
}
}
/// <summary>
/// 暂停指定类型的组件
/// </summary>
public void PauseComponents<T>() where T : ComponentBase
{
var components = _activeComponents.OfType<T>().ToList();
foreach (var component in components)
{
component.IsEnabled = false;
}
}
/// <summary>
/// 恢复指定类型的组件
/// </summary>
public void ResumeComponents<T>() where T : ComponentBase
{
var components = _activeComponents.OfType<T>().ToList();
foreach (var component in components)
{
component.IsEnabled = true;
}
}
/// <summary>
/// 销毁所有组件
/// </summary>
public void DestroyAllComponents()
{
var components = new List<ComponentBase>(_activeComponents);
foreach (var component in components)
{
UnregisterComponent(component);
}
}
#endregion
#region 查询
/// <summary>
/// 获取指定类型的所有组件
/// </summary>
public List<T> GetComponentsOfType<T>() where T : ComponentBase
{
return _activeComponents.OfType<T>().ToList();
}
/// <summary>
/// 查找组件
/// </summary>
public T FindComponent<T>(Func<T, bool> predicate) where T : ComponentBase
{
return _activeComponents.OfType<T>().FirstOrDefault(predicate);
}
#endregion
}
}
6.1.3 组件间通信
组件间通信是组件化架构的核心,通过事件系统和消息总线实现松耦合通信。
// 文件路径: Scripts/Framework/Components/Communication/MessageBus.cs
using Godot;
using System;
using System.Collections.Generic;
namespace GameFramework.Components.Communication
{
/// <summary>
/// 消息基类 - 所有组件间消息的基类
/// </summary>
public abstract class MessageBase
{
/// <summary>
/// 消息发送时间
/// </summary>
public float Timestamp { get; private set; }
/// <summary>
/// 消息发送者ID
/// </summary>
public string SenderId { get; set; }
/// <summary>
/// 消息是否已处理
/// </summary>
public bool IsHandled { get; set; }
protected MessageBase()
{
Timestamp = Time.GetTicksMsec() / 1000f;
}
/// <summary>
/// 标记消息为已处理
/// </summary>
public void MarkHandled()
{
IsHandled = true;
}
}
/// <summary>
/// 通用消息 - 用于简单的事件通知
/// </summary>
public class GenericMessage : MessageBase
{
/// <summary>
/// 消息类型标识
/// </summary>
public string MessageType { get; set; }
/// <summary>
/// 消息数据
/// </summary>
public Dictionary<string, object> Data { get; set; }
public GenericMessage(string messageType)
{
MessageType = messageType;
Data = new Dictionary<string, object>();
}
/// <summary>
/// 添加数据
/// </summary>
public GenericMessage WithData(string key, object value)
{
Data[key] = value;
return this;
}
}
/// <summary>
/// 消息总线 - 全局消息分发系统
/// </summary>
public class MessageBus : Node
{
#region 单例
private static MessageBus _instance;
public static MessageBus Instance
{
get
{
if (_instance == null)
{
_instance = new MessageBus();
Engine.RegisterSingleton(nameof(MessageBus), _instance);
}
return _instance;
}
}
#endregion
#region 委托和事件
/// <summary>
/// 消息处理委托
/// </summary>
public delegate void MessageHandler<T>(T message) where T : MessageBase;
/// <summary>
/// 通用消息处理委托
/// </summary>
public delegate void GenericMessageHandler(GenericMessage message);
#endregion
#region 字段
// 类型化消息处理器字典
private readonly Dictionary<Type, Delegate> _typedHandlers = new Dictionary<Type, Delegate>();
// 通用消息处理器字典 - 按消息类型分组
private readonly Dictionary<string, List<GenericMessageHandler>> _genericHandlers =
new Dictionary<string, List<GenericMessageHandler>>();
// 消息队列 - 用于延迟处理
private readonly Queue<MessageBase> _messageQueue = new Queue<MessageBase>();
// 处理器优先级字典
private readonly Dictionary<Delegate, int> _handlerPriorities = new Dictionary<Delegate, int>();
#endregion
#region 订阅
/// <summary>
/// 订阅类型化消息
/// </summary>
public void Subscribe<T>(MessageHandler<T> handler, int priority = 0) where T : MessageBase
{
var messageType = typeof(T);
if (!_typedHandlers.ContainsKey(messageType))
{
_typedHandlers[messageType] = null;
}
_typedHandlers[messageType] = (MessageHandler<T>)_typedHandlers[messageType] + handler;
_handlerPriorities[handler] = priority;
}
/// <summary>
/// 订阅通用消息
/// </summary>
public void Subscribe(string messageType, GenericMessageHandler handler)
{
if (!_genericHandlers.ContainsKey(messageType))
{
_genericHandlers[messageType] = new List<GenericMessageHandler>();
}
if (!_genericHandlers[messageType].Contains(handler))
{
_genericHandlers[messageType].Add(handler);
}
}
/// <summary>
/// 取消订阅类型化消息
/// </summary>
public void Unsubscribe<T>(MessageHandler<T> handler) where T : MessageBase
{
var messageType = typeof(T);
if (_typedHandlers.ContainsKey(messageType))
{
_typedHandlers[messageType] = (MessageHandler<T>)_typedHandlers[messageType] - handler;
_handlerPriorities.Remove(handler);
}
}
/// <summary>
/// 取消订阅通用消息
/// </summary>
public void Unsubscribe(string messageType, GenericMessageHandler handler)
{
if (_genericHandlers.ContainsKey(messageType))
{
_genericHandlers[messageType].Remove(handler);
}
}
#endregion
#region 发布
/// <summary>
/// 立即发布消息
/// </summary>
public void Publish<T>(T message) where T : MessageBase
{
var messageType = typeof(T);
// 处理类型化消息
if (_typedHandlers.ContainsKey(messageType) && _typedHandlers[messageType] != null)
{
var handler = (MessageHandler<T>)_typedHandlers[messageType];
handler?.Invoke(message);
}
// 处理通用消息
if (message is GenericMessage genericMessage)
{
PublishGeneric(genericMessage);
}
}
/// <summary>
/// 发布通用消息
/// </summary>
private void PublishGeneric(GenericMessage message)
{
if (_genericHandlers.ContainsKey(message.MessageType))
{
var handlers = _genericHandlers[message.MessageType];
foreach (var handler in handlers)
{
try
{
handler.Invoke(message);
// 如果消息被标记为已处理,停止传播
if (message.IsHandled)
break;
}
catch (Exception ex)
{
GD.PushError($"[MessageBus] 消息处理器异常: {ex.Message}");
}
}
}
}
/// <summary>
/// 延迟发布消息(下一帧处理)
/// </summary>
public void PublishDelayed<T>(T message) where T : MessageBase
{
_messageQueue.Enqueue(message);
}
/// <summary>
/// 每帧处理延迟消息
/// </summary>
public override void _Process(double delta)
{
// 处理延迟消息队列
while (_messageQueue.Count > 0)
{
var message = _messageQueue.Dequeue();
Publish(message);
}
}
#endregion
#region 查询
/// <summary>
/// 发布消息并等待结果
/// </summary>
public TResult Query<TMessage, TResult>(TMessage message, Func<TMessage, TResult> queryHandler) where TMessage : MessageBase
{
return queryHandler.Invoke(message);
}
/// <summary>
/// 是否存在指定类型的处理器
/// </summary>
public bool HasHandlers<T>() where T : MessageBase
{
return _typedHandlers.ContainsKey(typeof(T)) && _typedHandlers[typeof(T)] != null;
}
/// <summary>
/// 是否存在通用消息处理器
/// </summary>
public bool HasHandlers(string messageType)
{
return _genericHandlers.ContainsKey(messageType) && _genericHandlers[messageType].Count > 0;
}
#endregion
#region 清理
/// <summary>
/// 清理所有订阅
/// </summary>
public void ClearAllSubscriptions()
{
_typedHandlers.Clear();
_genericHandlers.Clear();
_handlerPriorities.Clear();
_messageQueue.Clear();
}
/// <summary>
/// 清理指定类型的订阅
/// </summary>
public void ClearSubscriptions<T>() where T : MessageBase
{
_typedHandlers.Remove(typeof(T));
}
/// <summary>
/// 清理指定通用消息的订阅
/// </summary>
public void ClearSubscriptions(string messageType)
{
_genericHandlers.Remove(messageType);
}
#endregion
}
}
使用示例:
// 文件路径: Scripts/Examples/ComponentCommunicationExample.cs
using Godot;
using GameFramework.Components;
using GameFramework.Components.Communication;
namespace GameFramework.Examples
{
/// <summary>
/// 生命值变化消息
/// </summary>
public class HealthChangedMessage : MessageBase
{
public int CurrentHealth { get; set; }
public int MaxHealth { get; set; }
public int ChangeAmount { get; set; }
}
/// <summary>
/// 健康组件 - 管理实体生命值
/// </summary>
public class HealthComponent : ComponentBase
{
private int _currentHealth = 100;
private int _maxHealth = 100;
public int CurrentHealth => _currentHealth;
public int MaxHealth => _maxHealth;
protected override void OnInitialize()
{
// 组件初始化完成
}
/// <summary>
/// 受到伤害
/// </summary>
public void TakeDamage(int damage)
{
int oldHealth = _currentHealth;
_currentHealth = Mathf.Max(0, _currentHealth - damage);
// 发布生命值变化消息
var message = new HealthChangedMessage
{
SenderId = ComponentId,
CurrentHealth = _currentHealth,
MaxHealth = _maxHealth,
ChangeAmount = _currentHealth - oldHealth
};
MessageBus.Instance.Publish(message);
if (_currentHealth <= 0)
{
// 发布死亡消息
MessageBus.Instance.Publish(new GenericMessage("EntityDied")
.WithData("EntityId", ComponentId));
}
}
/// <summary>
/// 治疗
/// </summary>
public void Heal(int amount)
{
int oldHealth = _currentHealth;
_currentHealth = Mathf.Min(_maxHealth, _currentHealth + amount);
// 发布生命值变化消息
var message = new HealthChangedMessage
{
SenderId = ComponentId,
CurrentHealth = _currentHealth,
MaxHealth = _maxHealth,
ChangeAmount = _currentHealth - oldHealth
};
MessageBus.Instance.Publish(message);
}
}
/// <summary>
/// UI 组件 - 显示生命值
/// </summary>
public class HealthUIComponent : ComponentBase
{
private Label _healthLabel;
private ProgressBar _healthBar;
protected override void OnInitialize()
{
// 订阅生命值变化消息
MessageBus.Instance.Subscribe<HealthChangedMessage>(OnHealthChanged);
// 创建UI元素
_healthLabel = new Label();
_healthBar = new ProgressBar();
AddChild(_healthLabel);
AddChild(_healthBar);
}
/// <summary>
/// 生命值变化回调
/// </summary>
private void OnHealthChanged(HealthChangedMessage message)
{
// 更新UI显示
_healthLabel.Text = $"HP: {message.CurrentHealth}/{message.MaxHealth}";
_healthBar.MaxValue = message.MaxHealth;
_healthBar.Value = message.CurrentHealth;
// 根据血量改变颜色
float healthPercent = (float)message.CurrentHealth / message.MaxHealth;
if (healthPercent < 0.3f)
{
_healthLabel.Modulate = Colors.Red;
}
else if (healthPercent < 0.6f)
{
_healthLabel.Modulate = Colors.Yellow;
}
else
{
_healthLabel.Modulate = Colors.Green;
}
}
protected override void OnDestroy()
{
// 取消订阅
MessageBus.Instance.Unsubscribe<HealthChangedMessage>(OnHealthChanged);
base.OnDestroy();
}
}
}
6.2 轻量级 ECS 模拟
ECS(Entity-Component-System)是游戏开发中广泛使用的高性能架构模式。本节实现一个适合 Godot C# 的轻量级 ECS 系统。
6.2.1 Entity 类设计
Entity 是 ECS 中的基本单位,本身不包含数据,仅作为组件的容器。
// 文件路径: Scripts/Framework/ECS/Entity.cs
using Godot;
using System;
using System.Collections.Generic;
namespace GameFramework.ECS
{
/// <summary>
/// 实体类 - ECS架构中的基本单位
/// 实体本身无状态,仅作为组件的容器和标识符
/// </summary>
public class Entity : IDisposable
{
#region 字段
// 实体唯一标识符
private readonly int _id;
// 实体名称(可选)
private string _name;
// 组件字典 - 按类型存储
private readonly Dictionary<Type, IComponent> _components = new Dictionary<Type, IComponent>();
// 组件列表 - 保持插入顺序
private readonly List<IComponent> _componentList = new List<IComponent>();
// 实体是否激活
private bool _isActive = true;
// 所属世界
private World _world;
// 实体创建时间
private readonly float _creationTime;
#endregion
#region 属性
/// <summary>
/// 实体唯一ID
/// </summary>
public int Id => _id;
/// <summary>
/// 实体名称
/// </summary>
public string Name
{
get => _name;
set => _name = value;
}
/// <summary>
/// 实体是否激活
/// </summary>
public bool IsActive
{
get => _isActive;
set
{
if (_isActive != value)
{
_isActive = value;
OnActiveStateChanged(value);
}
}
}
/// <summary>
/// 所属世界
/// </summary>
public World World => _world;
/// <summary>
/// 实体存活时间(秒)
/// </summary>
public float Lifetime => (Time.GetTicksMsec() / 1000f) - _creationTime;
/// <summary>
/// 组件数量
/// </summary>
public int ComponentCount => _components.Count;
#endregion
#region 构造函数
public Entity(int id, World world)
{
_id = id;
_world = world;
_creationTime = Time.GetTicksMsec() / 1000f;
_name = $"Entity_{id}";
}
#endregion
#region 组件管理
/// <summary>
/// 添加组件
/// </summary>
public T AddComponent<T>(T component) where T : class, IComponent
{
var type = typeof(T);
// 检查是否已存在该类型组件
if (_components.ContainsKey(type))
{
GD.PushWarning($"[Entity] 实体 {_id} 已存在组件类型 {type.Name},将替换旧组件");
RemoveComponent<T>();
}
// 设置组件的所属实体
component.Entity = this;
// 添加到字典和列表
_components[type] = component;
_componentList.Add(component);
// 通知世界组件已添加
_world?.OnComponentAdded(this, component);
// 调用组件初始化
component.Initialize();
return component;
}
/// <summary>
/// 添加组件(自动创建实例)
/// </summary>
public T AddComponent<T>() where T : class, IComponent, new()
{
return AddComponent(new T());
}
/// <summary>
/// 获取组件
/// </summary>
public T GetComponent<T>() where T : class, IComponent
{
if (_components.TryGetValue(typeof(T), out var component))
{
return component as T;
}
return null;
}
/// <summary>
/// 尝试获取组件
/// </summary>
public bool TryGetComponent<T>(out T component) where T : class, IComponent
{
component = GetComponent<T>();
return component != null;
}
/// <summary>
/// 检查是否拥有组件
/// </summary>
public bool HasComponent<T>() where T : class, IComponent
{
return _components.ContainsKey(typeof(T));
}
/// <summary>
/// 检查是否拥有所有指定类型的组件
/// </summary>
public bool HasComponents(params Type[] componentTypes)
{
foreach (var type in componentTypes)
{
if (!_components.ContainsKey(type))
return false;
}
return true;
}
/// <summary>
/// 移除组件
/// </summary>
public bool RemoveComponent<T>() where T : class, IComponent
{
var type = typeof(T);
if (_components.TryGetValue(type, out var component))
{
// 通知世界组件将被移除
_world?.OnComponentRemoved(this, component);
// 调用组件清理
component.Dispose();
// 从集合中移除
_components.Remove(type);
_componentList.Remove(component);
return true;
}
return false;
}
/// <summary>
/// 移除所有组件
/// </summary>
public void RemoveAllComponents()
{
// 倒序遍历以避免修改集合时的迭代问题
for (int i = _componentList.Count - 1; i >= 0; i--)
{
var component = _componentList[i];
_world?.OnComponentRemoved(this, component);
component.Dispose();
}
_components.Clear();
_componentList.Clear();
}
/// <summary>
/// 获取所有组件
/// </summary>
public IEnumerable<IComponent> GetAllComponents()
{
return _componentList;
}
/// <summary>
/// 替换组件
/// </summary>
public T ReplaceComponent<T>(T newComponent) where T : class, IComponent
{
RemoveComponent<T>();
return AddComponent(newComponent);
}
#endregion
#region 实体操作
/// <summary>
/// 克隆实体及其所有组件
/// </summary>
public Entity Clone()
{
var newEntity = _world.CreateEntity();
newEntity._name = _name + "_Clone";
// 克隆所有组件
foreach (var component in _componentList)
{
if (component is ICloneable cloneable)
{
var clonedComponent = cloneable.Clone() as IComponent;
if (clonedComponent != null)
{
// 使用反射获取组件类型并添加到新实体
var type = component.GetType();
var method = typeof(Entity).GetMethod(nameof(AddComponent), new[] { type });
method?.Invoke(newEntity, new object[] { clonedComponent });
}
}
}
return newEntity;
}
/// <summary>
/// 销毁实体
/// </summary>
public void Destroy()
{
// 从世界中移除
_world?.RemoveEntity(this);
// 清理资源
Dispose();
}
/// <summary>
/// 激活状态改变回调
/// </summary>
protected virtual void OnActiveStateChanged(bool active)
{
// 激活/禁用所有组件
foreach (var component in _componentList)
{
if (component is IActivatable activatable)
{
activatable.SetActive(active);
}
}
}
#endregion
#region IDisposable
public void Dispose()
{
RemoveAllComponents();
_world = null;
}
#endregion
#region 运算符重载
/// <summary>
/// 隐式转换为布尔值(检查实体是否有效)
/// </summary>
public static implicit operator bool(Entity entity)
{
return entity != null && entity._isActive;
}
/// <summary>
/// 相等性比较(基于ID)
/// </summary>
public override bool Equals(object obj)
{
return obj is Entity other && _id == other._id;
}
public override int GetHashCode()
{
return _id.GetHashCode();
}
public static bool operator ==(Entity a, Entity b)
{
if (ReferenceEquals(a, null) && ReferenceEquals(b, null))
return true;
if (ReferenceEquals(a, null) || ReferenceEquals(b, null))
return false;
return a._id == b._id;
}
public static bool operator !=(Entity a, Entity b)
{
return !(a == b);
}
#endregion
#region ToString
public override string ToString()
{
return $"Entity[{_id}] '{_name}' ({_components.Count} components)";
}
#endregion
}
}
6.2.2 组件接口定义
定义 ECS 组件的基础接口。
// 文件路径: Scripts/Framework/ECS/IComponent.cs
using System;
namespace GameFramework.ECS
{
/// <summary>
/// 组件接口 - ECS架构中所有组件必须实现的接口
/// </summary>
public interface IComponent : IDisposable
{
/// <summary>
/// 组件所属的实体
/// </summary>
Entity Entity { get; set; }
/// <summary>
/// 组件是否激活
/// </summary>
bool IsActive { get; }
/// <summary>
/// 初始化组件
/// </summary>
void Initialize();
/// <summary>
/// 设置激活状态
/// </summary>
void SetActive(bool active);
}
/// <summary>
/// 可激活接口
/// </summary>
public interface IActivatable
{
void SetActive(bool active);
}
/// <summary>
/// 可更新组件接口
/// </summary>
public interface IUpdatableComponent : IComponent
{
/// <summary>
/// 更新组件
/// </summary>
void Update(float deltaTime);
}
/// <summary>
/// 可固定更新组件接口
/// </summary>
public interface IFixedUpdatableComponent : IComponent
{
/// <summary>
/// 固定更新组件
/// </summary>
void FixedUpdate(float fixedDeltaTime);
}
}
6.2.3 System 类设计
System 负责处理具有特定组件组合的实体。
// 文件路径: Scripts/Framework/ECS/SystemBase.cs
using Godot;
using System;
using System.Collections.Generic;
namespace GameFramework.ECS
{
/// <summary>
/// 系统执行类型
/// </summary>
public enum SystemExecutionType
{
/// <summary>
/// 更新系统 - 每帧执行
/// </summary>
Update,
/// <summary>
/// 固定更新系统 - 固定时间间隔执行
/// </summary>
FixedUpdate,
/// <summary>
/// 渲染系统 - 渲染前执行
/// </summary>
Render,
/// <summary>
/// 事件系统 - 响应事件时执行
/// </summary>
Event
}
/// <summary>
/// 系统基类 - ECS架构中的处理器基类
/// </summary>
public abstract class SystemBase : IDisposable
{
#region 字段
// 系统优先级(数值越小优先级越高)
private int _priority = 0;
// 系统是否启用
private bool _isEnabled = true;
// 系统执行类型
private SystemExecutionType _executionType = SystemExecutionType.Update;
// 系统关注的组件类型
private readonly List<Type> _requiredComponentTypes = new List<Type>();
// 系统处理的实体列表
protected readonly List<Entity> _entities = new List<Entity>();
// 所属世界
protected World _world;
#endregion
#region 属性
/// <summary>
/// 系统优先级
/// </summary>
public int Priority
{
get => _priority;
set => _priority = value;
}
/// <summary>
/// 系统是否启用
/// </summary>
public bool IsEnabled
{
get => _isEnabled;
set => _isEnabled = value;
}
/// <summary>
/// 系统执行类型
/// </summary>
public SystemExecutionType ExecutionType => _executionType;
/// <summary>
/// 系统名称
/// </summary>
public virtual string SystemName => GetType().Name;
/// <summary>
/// 处理的实体数量
/// </summary>
public int EntityCount => _entities.Count;
#endregion
#region 构造函数
protected SystemBase(SystemExecutionType executionType = SystemExecutionType.Update)
{
_executionType = executionType;
}
#endregion
#region 抽象方法
/// <summary>
/// 初始化系统
/// </summary>
public abstract void Initialize(World world);
/// <summary>
/// 执行系统逻辑
/// </summary>
public abstract void Execute(float deltaTime);
/// <summary>
/// 系统启动时调用
/// </summary>
public virtual void OnStart() { }
/// <summary>
/// 系统停止时调用
/// </summary>
public virtual void OnStop() { }
/// <summary>
/// 实体进入系统时调用
/// </summary>
public virtual void OnEntityEnter(Entity entity) { }
/// <summary>
/// 实体离开系统时调用
/// </summary>
public virtual void OnEntityExit(Entity entity) { }
#endregion
#region 实体管理
/// <summary>
/// 添加实体到系统
/// </summary>
public void AddEntity(Entity entity)
{
if (!_entities.Contains(entity))
{
_entities.Add(entity);
OnEntityEnter(entity);
}
}
/// <summary>
/// 从系统移除实体
/// </summary>
public void RemoveEntity(Entity entity)
{
if (_entities.Remove(entity))
{
OnEntityExit(entity);
}
}
/// <summary>
/// 检查实体是否符合系统要求
/// </summary>
public bool IsEntityValid(Entity entity)
{
if (entity == null || !entity.IsActive)
return false;
foreach (var componentType in _requiredComponentTypes)
{
// 使用反射检查组件类型
var method = typeof(Entity).GetMethod(nameof(Entity.HasComponent));
var genericMethod = method.MakeGenericMethod(componentType);
var result = genericMethod.Invoke(entity, null);
if (!(bool)result)
return false;
}
return true;
}
/// <summary>
/// 刷新实体列表
/// </summary>
public void RefreshEntities()
{
// 移除无效实体
for (int i = _entities.Count - 1; i >= 0; i--)
{
if (!IsEntityValid(_entities[i]))
{
var entity = _entities[i];
_entities.RemoveAt(i);
OnEntityExit(entity);
}
}
}
/// <summary>
/// 添加必需的组件类型
/// </summary>
protected void RequireComponent<T>() where T : class, IComponent
{
_requiredComponentTypes.Add(typeof(T));
}
/// <summary>
/// 添加必需的组件类型
/// </summary>
protected void RequireComponent(Type componentType)
{
if (!typeof(IComponent).IsAssignableFrom(componentType))
{
throw new ArgumentException($"类型 {componentType.Name} 必须实现 IComponent 接口");
}
_requiredComponentTypes.Add(componentType);
}
#endregion
#region 工具方法
/// <summary>
/// 获取系统中的所有组件
/// </summary>
public IEnumerable<T> GetComponents<T>() where T : class, IComponent
{
foreach (var entity in _entities)
{
var component = entity.GetComponent<T>();
if (component != null)
{
yield return component;
}
}
}
/// <summary>
/// 获取实体组件
/// </summary>
protected T GetComponent<T>(Entity entity) where T : class, IComponent
{
return entity?.GetComponent<T>();
}
#endregion
#region IDisposable
public virtual void Dispose()
{
OnStop();
_entities.Clear();
_requiredComponentTypes.Clear();
}
#endregion
}
/// <summary>
/// 泛型系统基类 - 提供类型安全的组件访问
/// </summary>
public abstract class SystemBase<T1> : SystemBase
where T1 : class, IComponent
{
protected SystemBase(SystemExecutionType executionType = SystemExecutionType.Update)
: base(executionType)
{
RequireComponent<T1>();
}
/// <summary>
/// 获取组件
/// </summary>
protected T1 GetC1(Entity entity) => entity.GetComponent<T1>();
}
/// <summary>
/// 双组件系统基类
/// </summary>
public abstract class SystemBase<T1, T2> : SystemBase<T1>
where T1 : class, IComponent
where T2 : class, IComponent
{
protected SystemBase(SystemExecutionType executionType = SystemExecutionType.Update)
: base(executionType)
{
RequireComponent<T2>();
}
/// <summary>
/// 获取第二个组件
/// </summary>
protected T2 GetC2(Entity entity) => entity.GetComponent<T2>();
}
/// <summary>
/// 三组件系统基类
/// </summary>
public abstract class SystemBase<T1, T2, T3> : SystemBase<T1, T2>
where T1 : class, IComponent
where T2 : class, IComponent
where T3 : class, IComponent
{
protected SystemBase(SystemExecutionType executionType = SystemExecutionType.Update)
: base(executionType)
{
RequireComponent<T3>();
}
/// <summary>
/// 获取第三个组件
/// </summary>
protected T3 GetC3(Entity entity) => entity.GetComponent<T3>();
}
}
6.2.4 World 管理器
World 是 ECS 系统的核心管理器,负责协调实体、组件和系统。
// 文件路径: Scripts/Framework/ECS/World.cs
using Godot;
using System;
using System.Collections.Generic;
using System.Linq;
namespace GameFramework.ECS
{
/// <summary>
/// 世界类 - ECS架构的核心管理器
/// 负责管理所有实体、系统和组件的生命周期
/// </summary>
public class World : Node
{
#region 字段
// 实体字典
private readonly Dictionary<int, Entity> _entities = new Dictionary<int, Entity>();
// 系统列表
private readonly List<SystemBase> _updateSystems = new List<SystemBase>();
private readonly List<SystemBase> _fixedUpdateSystems = new List<SystemBase>();
private readonly List<SystemBase> _renderSystems = new List<SystemBase>();
// 实体ID生成器
private int _nextEntityId = 1;
// 待添加的实体队列
private readonly Queue<Entity> _pendingEntities = new Queue<Entity>();
// 待移除的实体队列
private readonly Queue<int> _pendingRemovals = new Queue<int>();
// 组件类型到包含该组件的实体的映射
private readonly Dictionary<Type, HashSet<Entity>> _componentEntityMap = new Dictionary<Type, HashSet<Entity>>();
// 世界是否正在运行
private bool _isRunning = false;
// 世界名称
private string _worldName;
#endregion
#region 属性
/// <summary>
/// 世界名称
/// </summary>
public string WorldName => _worldName ?? Name;
/// <summary>
/// 实体数量
/// </summary>
public int EntityCount => _entities.Count;
/// <summary>
/// 系统数量
/// </summary>
public int SystemCount => _updateSystems.Count + _fixedUpdateSystems.Count + _renderSystems.Count;
/// <summary>
/// 世界是否正在运行
/// </summary>
public bool IsRunning => _isRunning;
/// <summary>
/// 所有实体
/// </summary>
public IEnumerable<Entity> AllEntities => _entities.Values;
#endregion
#region Godot 生命周期
public override void _Ready()
{
base._Ready();
_worldName = Name;
// 设置处理模式
ProcessMode = ProcessModeEnum.Always;
GD.Print($"[World] 世界 '{WorldName}' 已创建");
}
public override void _Process(double delta)
{
if (!_isRunning) return;
float deltaTime = (float)delta;
// 处理待添加的实体
ProcessPendingEntities();
// 处理待移除的实体
ProcessPendingRemovals();
// 执行更新系统
ExecuteSystems(_updateSystems, deltaTime);
// 刷新所有系统的实体列表
RefreshAllSystems();
}
public override void _PhysicsProcess(double delta)
{
if (!_isRunning) return;
// 执行固定更新系统
ExecuteSystems(_fixedUpdateSystems, (float)delta);
}
public override void _ExitTree()
{
Stop();
Clear();
base._ExitTree();
}
#endregion
#region 实体管理
/// <summary>
/// 创建实体
/// </summary>
public Entity CreateEntity(string name = null)
{
var entity = new Entity(_nextEntityId++, this);
if (!string.IsNullOrEmpty(name))
{
entity.Name = name;
}
// 添加到待处理队列
_pendingEntities.Enqueue(entity);
GD.Print($"[World] 实体已创建: {entity}");
return entity;
}
/// <summary>
/// 获取实体
/// </summary>
public Entity GetEntity(int entityId)
{
_entities.TryGetValue(entityId, out var entity);
return entity;
}
/// <summary>
/// 移除实体
/// </summary>
public void RemoveEntity(Entity entity)
{
if (entity != null)
{
_pendingRemovals.Enqueue(entity.Id);
}
}
/// <summary>
/// 移除实体
/// </summary>
public bool RemoveEntity(int entityId)
{
if (_entities.TryGetValue(entityId, out var entity))
{
// 从所有系统中移除
RemoveEntityFromSystems(entity);
// 从组件映射中移除
RemoveEntityFromComponentMap(entity);
// 从字典中移除
_entities.Remove(entityId);
// 释放实体
entity.Dispose();
return true;
}
return false;
}
/// <summary>
/// 处理待添加的实体
/// </summary>
private void ProcessPendingEntities()
{
while (_pendingEntities.Count > 0)
{
var entity = _pendingEntities.Dequeue();
_entities[entity.Id] = entity;
// 将实体添加到匹配的系统
AddEntityToSystems(entity);
}
}
/// <summary>
/// 处理待移除的实体
/// </summary>
private void ProcessPendingRemovals()
{
while (_pendingRemovals.Count > 0)
{
var entityId = _pendingRemovals.Dequeue();
RemoveEntity(entityId);
}
}
/// <summary>
/// 清除所有实体
/// </summary>
public void ClearEntities()
{
// 标记所有实体为待移除
foreach (var entityId in _entities.Keys.ToList())
{
_pendingRemovals.Enqueue(entityId);
}
_pendingEntities.Clear();
}
#endregion
#region 系统管理
/// <summary>
/// 添加系统
/// </summary>
public void AddSystem(SystemBase system)
{
if (system == null) return;
// 初始化系统
system.Initialize(this);
// 根据执行类型添加到相应列表
switch (system.ExecutionType)
{
case SystemExecutionType.Update:
AddToSystemList(_updateSystems, system);
break;
case SystemExecutionType.FixedUpdate:
AddToSystemList(_fixedUpdateSystems, system);
break;
case SystemExecutionType.Render:
AddToSystemList(_renderSystems, system);
break;
}
// 将现有实体添加到新系统
foreach (var entity in _entities.Values)
{
if (system.IsEntityValid(entity))
{
system.AddEntity(entity);
}
}
system.OnStart();
GD.Print($"[World] 系统已添加: {system.SystemName}");
}
/// <summary>
/// 将系统添加到列表并按优先级排序
/// </summary>
private void AddToSystemList(List<SystemBase> systemList, SystemBase system)
{
systemList.Add(system);
systemList.Sort((a, b) => a.Priority.CompareTo(b.Priority));
}
/// <summary>
/// 移除系统
/// </summary>
public bool RemoveSystem(SystemBase system)
{
if (system == null) return false;
bool removed = false;
removed |= _updateSystems.Remove(system);
removed |= _fixedUpdateSystems.Remove(system);
removed |= _renderSystems.Remove(system);
if (removed)
{
system.OnStop();
system.Dispose();
}
return removed;
}
/// <summary>
/// 获取指定类型的系统
/// </summary>
public T GetSystem<T>() where T : SystemBase
{
foreach (var system in _updateSystems.OfType<T>()) return system;
foreach (var system in _fixedUpdateSystems.OfType<T>()) return system;
foreach (var system in _renderSystems.OfType<T>()) return system;
return null;
}
/// <summary>
/// 执行系统列表
/// </summary>
private void ExecuteSystems(List<SystemBase> systems, float deltaTime)
{
foreach (var system in systems)
{
if (system.IsEnabled)
{
system.Execute(deltaTime);
}
}
}
/// <summary>
/// 刷新所有系统的实体列表
/// </summary>
private void RefreshAllSystems()
{
RefreshSystemList(_updateSystems);
RefreshSystemList(_fixedUpdateSystems);
RefreshSystemList(_renderSystems);
}
/// <summary>
/// 刷新系统列表
/// </summary>
private void RefreshSystemList(List<SystemBase> systems)
{
foreach (var system in systems)
{
system.RefreshEntities();
}
}
#endregion
#region 组件管理
/// <summary>
/// 组件添加到实体时的回调
/// </summary>
internal void OnComponentAdded(Entity entity, IComponent component)
{
var componentType = component.GetType();
// 更新组件-实体映射
if (!_componentEntityMap.ContainsKey(componentType))
{
_componentEntityMap[componentType] = new HashSet<Entity>();
}
_componentEntityMap[componentType].Add(entity);
// 检查新组件是否使实体符合某个系统的要求
UpdateEntitySystems(entity);
}
/// <summary>
/// 组件从实体移除时的回调
/// </summary>
internal void OnComponentRemoved(Entity entity, IComponent component)
{
var componentType = component.GetType();
// 更新组件-实体映射
if (_componentEntityMap.ContainsKey(componentType))
{
_componentEntityMap[componentType].Remove(entity);
}
// 从不再符合要求的系统中移除实体
RemoveEntityFromSystems(entity);
}
/// <summary>
/// 获取拥有指定组件的所有实体
/// </summary>
public IEnumerable<Entity> GetEntitiesWithComponent<T>() where T : class, IComponent
{
var componentType = typeof(T);
if (_componentEntityMap.TryGetValue(componentType, out var entities))
{
return entities.Where(e => e.IsActive);
}
return Enumerable.Empty<Entity>();
}
/// <summary>
/// 获取拥有所有指定组件的实体
/// </summary>
public IEnumerable<Entity> GetEntitiesWithComponents(params Type[] componentTypes)
{
if (componentTypes.Length == 0)
return Enumerable.Empty<Entity>();
// 从第一个组件类型的实体开始
if (!_componentEntityMap.TryGetValue(componentTypes[0], out var candidates))
return Enumerable.Empty<Entity>();
// 过滤出拥有所有其他组件的实体
return candidates.Where(entity =>
{
for (int i = 1; i < componentTypes.Length; i++)
{
var type = componentTypes[i];
if (!_componentEntityMap.TryGetValue(type, out var entities) ||
!entities.Contains(entity))
{
return false;
}
}
return entity.IsActive;
});
}
#endregion
#region 系统-实体关联
/// <summary>
/// 将实体添加到所有匹配的系统
/// </summary>
private void AddEntityToSystems(Entity entity)
{
AddEntityToSystemList(entity, _updateSystems);
AddEntityToSystemList(entity, _fixedUpdateSystems);
AddEntityToSystemList(entity, _renderSystems);
}
/// <summary>
/// 将实体添加到系统列表
/// </summary>
private void AddEntityToSystemList(Entity entity, List<SystemBase> systems)
{
foreach (var system in systems)
{
if (system.IsEntityValid(entity))
{
system.AddEntity(entity);
}
}
}
/// <summary>
/// 从所有系统中移除实体
/// </summary>
private void RemoveEntityFromSystems(Entity entity)
{
RemoveEntityFromSystemList(entity, _updateSystems);
RemoveEntityFromSystemList(entity, _fixedUpdateSystems);
RemoveEntityFromSystemList(entity, _renderSystems);
}
/// <summary>
/// 从系统列表中移除实体
/// </summary>
private void RemoveEntityFromSystemList(Entity entity, List<SystemBase> systems)
{
foreach (var system in systems)
{
system.RemoveEntity(entity);
}
}
/// <summary>
/// 更新实体所属的系统
/// </summary>
private void UpdateEntitySystems(Entity entity)
{
UpdateEntitySystemsInList(entity, _updateSystems);
UpdateEntitySystemsInList(entity, _fixedUpdateSystems);
UpdateEntitySystemsInList(entity, _renderSystems);
}
/// <summary>
/// 在系统列表中更新实体
/// </summary>
private void UpdateEntitySystemsInList(Entity entity, List<SystemBase> systems)
{
foreach (var system in systems)
{
bool isValid = system.IsEntityValid(entity);
bool isInSystem = system.EntityCount > 0 &&
// 这里简化处理,实际应该检查具体是否包含该实体
true;
if (isValid && !isInSystem)
{
system.AddEntity(entity);
}
else if (!isValid && isInSystem)
{
system.RemoveEntity(entity);
}
}
}
#endregion
#region 组件映射管理
/// <summary>
/// 从组件映射中移除实体
/// </summary>
private void RemoveEntityFromComponentMap(Entity entity)
{
foreach (var kvp in _componentEntityMap)
{
kvp.Value.Remove(entity);
}
}
#endregion
#region 世界控制
/// <summary>
/// 启动世界
/// </summary>
public void Start()
{
if (_isRunning) return;
_isRunning = true;
// 启动所有系统
foreach (var system in _updateSystems) system.OnStart();
foreach (var system in _fixedUpdateSystems) system.OnStart();
foreach (var system in _renderSystems) system.OnStart();
GD.Print($"[World] 世界 '{WorldName}' 已启动");
}
/// <summary>
/// 停止世界
/// </summary>
public void Stop()
{
if (!_isRunning) return;
_isRunning = false;
// 停止所有系统
foreach (var system in _updateSystems) system.OnStop();
foreach (var system in _fixedUpdateSystems) system.OnStop();
foreach (var system in _renderSystems) system.OnStop();
GD.Print($"[World] 世界 '{WorldName}' 已停止");
}
/// <summary>
/// 暂停世界
/// </summary>
public void Pause()
{
_isRunning = false;
}
/// <summary>
/// 恢复世界
/// </summary>
public void Resume()
{
_isRunning = true;
}
/// <summary>
/// 清除所有数据
/// </summary>
public void Clear()
{
Stop();
// 清除实体
ClearEntities();
ProcessPendingRemovals();
// 清除系统
var allSystems = new List<SystemBase>(_updateSystems);
allSystems.AddRange(_fixedUpdateSystems);
allSystems.AddRange(_renderSystems);
foreach (var system in allSystems)
{
system.Dispose();
}
_updateSystems.Clear();
_fixedUpdateSystems.Clear();
_renderSystems.Clear();
// 清除组件映射
_componentEntityMap.Clear();
GD.Print($"[World] 世界 '{WorldName}' 已清除");
}
#endregion
}
}
ECS 使用示例:
// 文件路径: Scripts/Examples/ECSExample.cs
using Godot;
using GameFramework.ECS;
namespace GameFramework.Examples
{
// ============================================
// 组件定义
// ============================================
/// <summary>
/// 变换组件 - 实体的位置和旋转
/// </summary>
public class TransformComponent : IComponent
{
public Entity Entity { get; set; }
public bool IsActive { get; private set; } = true;
public Vector3 Position { get; set; } = Vector3.Zero;
public Vector3 Rotation { get; set; } = Vector3.Zero;
public Vector3 Scale { get; set; } = Vector3.One;
public void Initialize()
{
GD.Print($"[TransformComponent] 组件已初始化");
}
public void SetActive(bool active)
{
IsActive = active;
}
public void Dispose()
{
// 清理资源
}
}
/// <summary>
/// 移动组件 - 控制实体移动
/// </summary>
public class MovementComponent : IComponent, IUpdatableComponent
{
public Entity Entity { get; set; }
public bool IsActive { get; private set; } = true;
public Vector3 Velocity { get; set; } = Vector3.Zero;
public float Speed { get; set; } = 5.0f;
public Vector3 TargetDirection { get; set; } = Vector3.Forward;
public void Initialize()
{
GD.Print($"[MovementComponent] 组件已初始化");
}
public void Update(float deltaTime)
{
if (!IsActive) return;
// 更新速度
Velocity = TargetDirection.Normalized() * Speed;
}
public void SetActive(bool active)
{
IsActive = active;
}
public void Dispose()
{
Velocity = Vector3.Zero;
}
}
/// <summary>
/// 渲染组件 - 实体的视觉表现
/// </summary>
public class RenderComponent : IComponent
{
public Entity Entity { get; set; }
public bool IsActive { get; private set; } = true;
public string SpritePath { get; set; }
public Color Tint { get; set; } = Colors.White;
public bool Visible { get; set; } = true;
public void Initialize()
{
GD.Print($"[RenderComponent] 组件已初始化,Sprite: {SpritePath}");
}
public void SetActive(bool active)
{
IsActive = active;
}
public void Dispose()
{
// 清理渲染资源
}
}
// ============================================
// 系统定义
// ============================================
/// <summary>
/// 移动系统 - 处理实体的移动逻辑
/// </summary>
public class MovementSystem : SystemBase<TransformComponent, MovementComponent>
{
public MovementSystem() : base(SystemExecutionType.Update)
{
Priority = 10; // 较低的优先级
}
public override void Initialize(World world)
{
_world = world;
GD.Print("[MovementSystem] 系统已初始化");
}
public override void Execute(float deltaTime)
{
// 遍历系统中的所有实体
foreach (var entity in _entities)
{
var transform = GetC1(entity);
var movement = GetC2(entity);
// 更新位置
transform.Position += movement.Velocity * deltaTime;
// 如果移动了,打印位置
if (movement.Velocity.LengthSquared() > 0.001f)
{
GD.Print($"[MovementSystem] 实体 {entity.Name} 位置: {transform.Position}");
}
}
}
}
/// <summary>
/// 渲染系统 - 处理实体的渲染
/// </summary>
public class RenderSystem : SystemBase<TransformComponent, RenderComponent>
{
public RenderSystem() : base(SystemExecutionType.Render)
{
Priority = 100; // 渲染系统优先级较低
}
public override void Initialize(World world)
{
_world = world;
GD.Print("[RenderSystem] 系统已初始化");
}
public override void Execute(float deltaTime)
{
foreach (var entity in _entities)
{
var transform = GetC1(entity);
var render = GetC2(entity);
if (render.Visible)
{
// 在这里执行实际的渲染逻辑
// 例如更新Godot节点的位置和显示
}
}
}
}
// ============================================
// 使用示例
// ============================================
public class ECSExample : Node
{
private World _world;
public override void _Ready()
{
// 创建世界
_world = new World();
_world.Name = "GameWorld";
AddChild(_world);
// 创建系统
var movementSystem = new MovementSystem();
var renderSystem = new RenderSystem();
// 添加系统到世界
_world.AddSystem(movementSystem);
_world.AddSystem(renderSystem);
// 创建玩家实体
CreatePlayer();
// 创建敌人实体
CreateEnemy();
// 启动世界
_world.Start();
}
/// <summary>
/// 创建玩家实体
/// </summary>
private void CreatePlayer()
{
var player = _world.CreateEntity("Player");
// 添加变换组件
player.AddComponent(new TransformComponent
{
Position = new Vector3(0, 0, 0),
Scale = Vector3.One
});
// 添加移动组件
player.AddComponent(new MovementComponent
{
Speed = 10.0f,
TargetDirection = new Vector3(1, 0, 0) // 向右移动
});
// 添加渲染组件
player.AddComponent(new RenderComponent
{
SpritePath = "res://Sprites/Player.png",
Tint = Colors.Blue,
Visible = true
});
GD.Print($"[ECSExample] 玩家实体已创建: {player}");
}
/// <summary>
/// 创建敌人实体
/// </summary>
private void CreateEnemy()
{
var enemy = _world.CreateEntity("Enemy");
// 添加变换组件
enemy.AddComponent(new TransformComponent
{
Position = new Vector3(10, 0, 0),
Scale = new Vector3(1.5f, 1.5f, 1.5f)
});
// 添加移动组件
enemy.AddComponent(new MovementComponent
{
Speed = 3.0f,
TargetDirection = new Vector3(-1, 0, 0) // 向左移动
});
// 添加渲染组件
enemy.AddComponent(new RenderComponent
{
SpritePath = "res://Sprites/Enemy.png",
Tint = Colors.Red,
Visible = true
});
GD.Print($"[ECSExample] 敌人实体已创建: {enemy}");
}
public override void _ExitTree()
{
_world?.Clear();
}
}
}
6.3 依赖注入容器
依赖注入(DI)是一种实现控制反转的设计模式,通过容器管理对象的创建和依赖关系。
6.3.1 DI Container 实现
// 文件路径: Scripts/Framework/DI/DependencyContainer.cs
using Godot;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace GameFramework.DI
{
/// <summary>
/// 服务生命周期类型
/// </summary>
public enum ServiceLifetime
{
/// <summary>
/// 单例 - 整个应用程序生命周期内只有一个实例
/// </summary>
Singleton,
/// <summary>
/// 瞬态 - 每次请求都创建新实例
/// </summary>
Transient,
/// <summary>
/// 作用域 - 在同一作用域内共享实例
/// </summary>
Scoped
}
/// <summary>
/// 服务注册信息
/// </summary>
public class ServiceRegistration
{
/// <summary>
/// 服务类型
/// </summary>
public Type ServiceType { get; set; }
/// <summary>
/// 实现类型
/// </summary>
public Type ImplementationType { get; set; }
/// <summary>
/// 服务生命周期
/// </summary>
public ServiceLifetime Lifetime { get; set; }
/// <summary>
/// 工厂方法
/// </summary>
public Func<DependencyContainer, object> Factory { get; set; }
/// <summary>
/// 单例实例
/// </summary>
public object SingletonInstance { get; set; }
/// <summary>
/// 服务名称(可选,用于区分同一类型的多个注册)
/// </summary>
public string Name { get; set; }
}
/// <summary>
/// 依赖注入容器 - 管理服务的注册和解析
/// </summary>
public class DependencyContainer
{
#region 字段
// 服务注册字典 - 按服务类型分组
private readonly Dictionary<Type, List<ServiceRegistration>> _registrations =
new Dictionary<Type, List<ServiceRegistration>>();
// 单例实例缓存
private readonly Dictionary<ServiceRegistration, object> _singletonInstances =
new Dictionary<ServiceRegistration, object>();
// 作用域实例缓存
private readonly Dictionary<string, Dictionary<ServiceRegistration, object>> _scopedInstances =
new Dictionary<string, Dictionary<ServiceRegistration, object>>();
// 当前作用域ID
private string _currentScopeId = null;
// 父容器(用于作用域嵌套)
private readonly DependencyContainer _parentContainer;
// 已解析的类型栈(用于检测循环依赖)
private readonly HashSet<Type> _resolutionStack = new HashSet<Type>();
#endregion
#region 构造函数
public DependencyContainer()
{
}
/// <summary>
/// 创建子容器(用于创建作用域)
/// </summary>
private DependencyContainer(DependencyContainer parent)
{
_parentContainer = parent;
}
#endregion
#region 注册服务
/// <summary>
/// 注册服务(类型映射)
/// </summary>
public ServiceRegistration Register<TService, TImplementation>(ServiceLifetime lifetime = ServiceLifetime.Transient, string name = null)
where TService : class
where TImplementation : class, TService
{
return Register(typeof(TService), typeof(TImplementation), lifetime, name);
}
/// <summary>
/// 注册服务(类型映射)
/// </summary>
public ServiceRegistration Register(Type serviceType, Type implementationType, ServiceLifetime lifetime = ServiceLifetime.Transient, string name = null)
{
if (!serviceType.IsAssignableFrom(implementationType) && !serviceType.IsInterface)
{
throw new ArgumentException($"类型 {implementationType.Name} 不实现 {serviceType.Name}");
}
var registration = new ServiceRegistration
{
ServiceType = serviceType,
ImplementationType = implementationType,
Lifetime = lifetime,
Name = name
};
AddRegistration(serviceType, registration);
return registration;
}
/// <summary>
/// 注册服务(实例)
/// </summary>
public ServiceRegistration RegisterInstance<TService>(TService instance, string name = null) where TService : class
{
return RegisterInstance(typeof(TService), instance, name);
}
/// <summary>
/// 注册服务(实例)
/// </summary>
public ServiceRegistration RegisterInstance(Type serviceType, object instance, string name = null)
{
if (instance == null)
throw new ArgumentNullException(nameof(instance));
if (!serviceType.IsAssignableFrom(instance.GetType()))
{
throw new ArgumentException($"实例类型 {instance.GetType().Name} 不兼容 {serviceType.Name}");
}
var registration = new ServiceRegistration
{
ServiceType = serviceType,
ImplementationType = instance.GetType(),
Lifetime = ServiceLifetime.Singleton,
SingletonInstance = instance,
Name = name
};
AddRegistration(serviceType, registration);
return registration;
}
/// <summary>
/// 注册服务(工厂方法)
/// </summary>
public ServiceRegistration RegisterFactory<TService>(Func<DependencyContainer, TService> factory, ServiceLifetime lifetime = ServiceLifetime.Transient, string name = null) where TService : class
{
var registration = new ServiceRegistration
{
ServiceType = typeof(TService),
ImplementationType = typeof(TService),
Lifetime = lifetime,
Factory = container => factory(container),
Name = name
};
AddRegistration(typeof(TService), registration);
return registration;
}
/// <summary>
/// 注册自身类型
/// </summary>
public ServiceRegistration RegisterSelf<TImplementation>(ServiceLifetime lifetime = ServiceLifetime.Transient) where TImplementation : class
{
return Register<TImplementation, TImplementation>(lifetime);
}
/// <summary>
/// 添加注册信息到字典
/// </summary>
private void AddRegistration(Type serviceType, ServiceRegistration registration)
{
if (!_registrations.ContainsKey(serviceType))
{
_registrations[serviceType] = new List<ServiceRegistration>();
}
// 如果同名服务已存在,移除旧注册
_registrations[serviceType].RemoveAll(r => r.Name == registration.Name);
_registrations[serviceType].Add(registration);
GD.Print($"[DI] 服务已注册: {serviceType.Name} -> {registration.ImplementationType.Name} ({registration.Lifetime})");
}
#endregion
#region 解析服务
/// <summary>
/// 解析服务
/// </summary>
public TService Resolve<TService>(string name = null) where TService : class
{
return (TService)Resolve(typeof(TService), name);
}
/// <summary>
/// 解析服务
/// </summary>
public object Resolve(Type serviceType, string name = null)
{
// 检测循环依赖
if (_resolutionStack.Contains(serviceType))
{
throw new InvalidOperationException($"检测到循环依赖: {string.Join(" -> ", _resolutionStack)} -> {serviceType.Name}");
}
// 检查父容器
if (_parentContainer != null)
{
try
{
return _parentContainer.Resolve(serviceType, name);
}
catch { }
}
// 查找注册信息
var registration = GetRegistration(serviceType, name);
if (registration == null)
{
// 如果没有注册但类型可以实例化,自动注册为瞬态
if (!serviceType.IsAbstract && !serviceType.IsInterface)
{
return CreateInstance(serviceType);
}
throw new InvalidOperationException($"未找到服务 {serviceType.Name} 的注册信息");
}
// 根据生命周期创建或获取实例
_resolutionStack.Add(serviceType);
try
{
return GetOrCreateInstance(registration);
}
finally
{
_resolutionStack.Remove(serviceType);
}
}
/// <summary>
/// 尝试解析服务
/// </summary>
public bool TryResolve<TService>(out TService service, string name = null) where TService : class
{
try
{
service = Resolve<TService>(name);
return service != null;
}
catch
{
service = null;
return false;
}
}
/// <summary>
/// 解析所有实现
/// </summary>
public IEnumerable<TService> ResolveAll<TService>() where TService : class
{
return ResolveAll(typeof(TService)).Cast<TService>();
}
/// <summary>
/// 解析所有实现
/// </summary>
public IEnumerable<object> ResolveAll(Type serviceType)
{
if (_registrations.TryGetValue(serviceType, out var registrations))
{
foreach (var registration in registrations)
{
yield return GetOrCreateInstance(registration);
}
}
}
/// <summary>
/// 获取注册信息
/// </summary>
private ServiceRegistration GetRegistration(Type serviceType, string name)
{
if (_registrations.TryGetValue(serviceType, out var registrations))
{
if (name != null)
{
return registrations.FirstOrDefault(r => r.Name == name);
}
return registrations.FirstOrDefault();
}
return null;
}
/// <summary>
/// 获取或创建实例
/// </summary>
private object GetOrCreateInstance(ServiceRegistration registration)
{
switch (registration.Lifetime)
{
case ServiceLifetime.Singleton:
return GetOrCreateSingleton(registration);
case ServiceLifetime.Scoped:
return GetOrCreateScoped(registration);
case ServiceLifetime.Transient:
default:
return CreateInstance(registration);
}
}
/// <summary>
/// 获取或创建单例
/// </summary>
private object GetOrCreateSingleton(ServiceRegistration registration)
{
if (registration.SingletonInstance != null)
return registration.SingletonInstance;
if (_singletonInstances.TryGetValue(registration, out var instance))
return instance;
instance = CreateInstance(registration);
_singletonInstances[registration] = instance;
return instance;
}
/// <summary>
/// 获取或创建作用域实例
/// </summary>
private object GetOrCreateScoped(ServiceRegistration registration)
{
if (_currentScopeId == null)
{
throw new InvalidOperationException("尝试在作用域外解析作用域服务");
}
if (!_scopedInstances.TryGetValue(_currentScopeId, out var scope))
{
scope = new Dictionary<ServiceRegistration, object>();
_scopedInstances[_currentScopeId] = scope;
}
if (scope.TryGetValue(registration, out var instance))
return instance;
instance = CreateInstance(registration);
scope[registration] = instance;
return instance;
}
/// <summary>
/// 创建实例
/// </summary>
private object CreateInstance(ServiceRegistration registration)
{
if (registration.Factory != null)
{
return registration.Factory(this);
}
return CreateInstance(registration.ImplementationType);
}
/// <summary>
/// 创建类型实例(自动注入依赖)
/// </summary>
private object CreateInstance(Type implementationType)
{
// 获取构造函数
var constructors = implementationType.GetConstructors();
if (constructors.Length == 0)
{
throw new InvalidOperationException($"类型 {implementationType.Name} 没有公共构造函数");
}
// 选择参数最多的构造函数
var constructor = constructors.OrderByDescending(c => c.GetParameters().Length).First();
var parameters = constructor.GetParameters();
// 解析参数
var args = new object[parameters.Length];
for (int i = 0; i < parameters.Length; i++)
{
var param = parameters[i];
var injectAttribute = param.GetCustomAttribute<InjectAttribute>();
string serviceName = injectAttribute?.Name;
args[i] = Resolve(param.ParameterType, serviceName);
}
// 创建实例
var instance = constructor.Invoke(args);
// 执行属性注入
InjectProperties(instance);
// 执行字段注入
InjectFields(instance);
// 调用初始化方法
InvokeInitializeMethods(instance);
return instance;
}
#endregion
#region 属性注入
/// <summary>
/// 注入属性
/// </summary>
private void InjectProperties(object instance)
{
var properties = instance.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(p => p.CanWrite && p.GetCustomAttribute<InjectAttribute>() != null);
foreach (var property in properties)
{
var injectAttribute = property.GetCustomAttribute<InjectAttribute>();
try
{
var value = Resolve(property.PropertyType, injectAttribute?.Name);
property.SetValue(instance, value);
}
catch (Exception ex)
{
if (!injectAttribute?.Optional ?? true)
{
throw new InvalidOperationException(
$"无法注入属性 {property.Name} 到类型 {instance.GetType().Name}", ex);
}
}
}
}
#endregion
#region 字段注入
/// <summary>
/// 注入字段
/// </summary>
private void InjectFields(object instance)
{
var fields = instance.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.Where(f => f.GetCustomAttribute<InjectAttribute>() != null);
foreach (var field in fields)
{
var injectAttribute = field.GetCustomAttribute<InjectAttribute>();
try
{
var value = Resolve(field.FieldType, injectAttribute?.Name);
field.SetValue(instance, value);
}
catch (Exception ex)
{
if (!injectAttribute?.Optional ?? true)
{
throw new InvalidOperationException(
$"无法注入字段 {field.Name} 到类型 {instance.GetType().Name}", ex);
}
}
}
}
#endregion
#region 初始化方法
/// <summary>
/// 调用标记了[Initialize]的方法
/// </summary>
private void InvokeInitializeMethods(object instance)
{
var methods = instance.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance)
.Where(m => m.GetCustomAttribute<InitializeAttribute>() != null);
foreach (var method in methods)
{
// 解析方法参数
var parameters = method.GetParameters();
var args = new object[parameters.Length];
for (int i = 0; i < parameters.Length; i++)
{
var param = parameters[i];
var injectAttribute = param.GetCustomAttribute<InjectAttribute>();
args[i] = Resolve(param.ParameterType, injectAttribute?.Name);
}
method.Invoke(instance, args);
}
}
#endregion
#region 作用域管理
/// <summary>
/// 创建作用域
/// </summary>
public Scope CreateScope()
{
return new Scope(this);
}
/// <summary>
/// 设置当前作用域
/// </summary>
internal void SetCurrentScope(string scopeId)
{
_currentScopeId = scopeId;
}
/// <summary>
/// 清除作用域实例
/// </summary>
internal void ClearScope(string scopeId)
{
if (_scopedInstances.TryGetValue(scopeId, out var instances))
{
// 释放可释放的实例
foreach (var instance in instances.Values)
{
if (instance is IDisposable disposable)
{
disposable.Dispose();
}
}
instances.Clear();
_scopedInstances.Remove(scopeId);
}
}
#endregion
#region 构建提供者
/// <summary>
/// 构建服务提供者
/// </summary>
public IServiceProvider BuildServiceProvider()
{
return new DIServiceProvider(this);
}
#endregion
#region 清理
/// <summary>
/// 释放所有单例实例
/// </summary>
public void Dispose()
{
// 释放单例
foreach (var instance in _singletonInstances.Values)
{
if (instance is IDisposable disposable)
{
disposable.Dispose();
}
}
_singletonInstances.Clear();
// 释放所有作用域
foreach (var scopeId in _scopedInstances.Keys.ToList())
{
ClearScope(scopeId);
}
_scopedInstances.Clear();
_registrations.Clear();
}
#endregion
}
/// <summary>
/// 作用域 - 管理作用域生命周期
/// </summary>
public class Scope : IDisposable
{
private readonly DependencyContainer _container;
private readonly string _scopeId;
private bool _disposed = false;
internal Scope(DependencyContainer container)
{
_container = container;
_scopeId = Guid.NewGuid().ToString("N");
_container.SetCurrentScope(_scopeId);
}
/// <summary>
/// 解析服务
/// </summary>
public TService Resolve<TService>(string name = null) where TService : class
{
if (_disposed)
throw new ObjectDisposedException(nameof(Scope));
_container.SetCurrentScope(_scopeId);
return _container.Resolve<TService>(name);
}
/// <summary>
/// 释放作用域
/// </summary>
public void Dispose()
{
if (_disposed) return;
_container.ClearScope(_scopeId);
_container.SetCurrentScope(null);
_disposed = true;
}
}
}
6.3.2 [Inject] 特性
// 文件路径: Scripts/Framework/DI/Attributes.cs
using System;
namespace GameFramework.DI
{
/// <summary>
/// 注入特性 - 标记需要依赖注入的构造函数、属性、字段或方法参数
/// </summary>
[AttributeUsage(AttributeTargets.Constructor | AttributeTargets.Property |
AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]
public class InjectAttribute : Attribute
{
/// <summary>
/// 服务名称(可选)
/// </summary>
public string Name { get; set; }
/// <summary>
/// 是否可选(如果为true,注入失败不会抛出异常)
/// </summary>
public bool Optional { get; set; }
public InjectAttribute()
{
}
public InjectAttribute(string name)
{
Name = name;
}
}
/// <summary>
/// 初始化特性 - 标记服务创建后需要调用的初始化方法
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class InitializeAttribute : Attribute
{
/// <summary>
/// 初始化优先级(数值越小越早执行)
/// </summary>
public int Priority { get; set; }
public InitializeAttribute(int priority = 0)
{
Priority = priority;
}
}
/// <summary>
/// 单例特性 - 标记类为单例服务
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public class SingletonAttribute : Attribute
{
/// <summary>
/// 服务类型(如果与实现类型不同)
/// </summary>
public Type ServiceType { get; set; }
public SingletonAttribute()
{
}
public SingletonAttribute(Type serviceType)
{
ServiceType = serviceType;
}
}
/// <summary>
/// 瞬态特性 - 标记类为瞬态服务
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public class TransientAttribute : Attribute
{
/// <summary>
/// 服务类型(如果与实现类型不同)
/// </summary>
public Type ServiceType { get; set; }
public TransientAttribute()
{
}
public TransientAttribute(Type serviceType)
{
ServiceType = serviceType;
}
}
}
6.3.3 服务注册与获取
// 文件路径: Scripts/Framework/DI/ServiceProvider.cs
using System;
using System.Collections.Generic;
namespace GameFramework.DI
{
/// <summary>
/// 服务提供者接口
/// </summary>
public interface IServiceProvider
{
/// <summary>
/// 获取服务
/// </summary>
T GetService<T>() where T : class;
/// <summary>
/// 获取服务
/// </summary>
object GetService(Type serviceType);
/// <summary>
/// 获取命名服务
/// </summary>
T GetService<T>(string name) where T : class;
/// <summary>
/// 获取所有服务实现
/// </summary>
IEnumerable<T> GetServices<T>() where T : class;
}
/// <summary>
/// DI服务提供者实现
/// </summary>
public class DIServiceProvider : IServiceProvider
{
private readonly DependencyContainer _container;
public DIServiceProvider(DependencyContainer container)
{
_container = container;
}
public T GetService<T>() where T : class
{
return _container.Resolve<T>();
}
public object GetService(Type serviceType)
{
return _container.Resolve(serviceType);
}
public T GetService<T>(string name) where T : class
{
return _container.Resolve<T>(name);
}
public IEnumerable<T> GetServices<T>() where T : class
{
return _container.ResolveAll<T>();
}
}
}
DI 使用示例:
// 文件路径: Scripts/Examples/DIExample.cs
using Godot;
using GameFramework.DI;
namespace GameFramework.Examples
{
// ============================================
// 服务接口和实现
// ============================================
/// <summary>
/// 游戏配置服务接口
/// </summary>
public interface IGameConfigService
{
string GameVersion { get; }
int MaxPlayers { get; }
float DefaultMoveSpeed { get; }
}
/// <summary>
/// 游戏配置服务实现
/// </summary>
public class GameConfigService : IGameConfigService
{
public string GameVersion { get; } = "1.0.0";
public int MaxPlayers { get; } = 100;
public float DefaultMoveSpeed { get; } = 5.0f;
}
/// <summary>
/// 玩家数据服务接口
/// </summary>
public interface IPlayerDataService
{
void LoadPlayerData(string playerId);
void SavePlayerData(string playerId);
PlayerData GetPlayerData(string playerId);
}
/// <summary>
/// 玩家数据
/// </summary>
public class PlayerData
{
public string PlayerId { get; set; }
public string PlayerName { get; set; }
public int Level { get; set; }
public int Experience { get; set; }
}
/// <summary>
/// 玩家数据服务实现
/// </summary>
public class PlayerDataService : IPlayerDataService
{
// 通过属性注入
[Inject]
public IGameConfigService ConfigService { get; set; }
private readonly Dictionary<string, PlayerData> _playerDataCache = new Dictionary<string, PlayerData>();
[Initialize]
public void Initialize()
{
GD.Print($"[PlayerDataService] 已初始化,游戏版本: {ConfigService?.GameVersion}");
}
public void LoadPlayerData(string playerId)
{
// 模拟从存储加载
var data = new PlayerData
{
PlayerId = playerId,
PlayerName = $"Player_{playerId}",
Level = 1,
Experience = 0
};
_playerDataCache[playerId] = data;
GD.Print($"[PlayerDataService] 玩家数据已加载: {playerId}");
}
public void SavePlayerData(string playerId)
{
GD.Print($"[PlayerDataService] 玩家数据已保存: {playerId}");
}
public PlayerData GetPlayerData(string playerId)
{
return _playerDataCache.TryGetValue(playerId, out var data) ? data : null;
}
}
/// <summary>
/// 音频服务
/// </summary>
public interface IAudioService
{
void PlaySound(string soundId);
void StopSound(string soundId);
void SetVolume(float volume);
}
public class AudioService : IAudioService
{
private float _volume = 1.0f;
public void PlaySound(string soundId)
{
GD.Print($"[AudioService] 播放音效: {soundId} (音量: {_volume})");
}
public void StopSound(string soundId)
{
GD.Print($"[AudioService] 停止音效: {soundId}");
}
public void SetVolume(float volume)
{
_volume = Mathf.Clamp(volume, 0, 1);
}
}
// ============================================
// 使用依赖注入的类
// ============================================
/// <summary>
/// 玩家管理器 - 使用构造函数注入
/// </summary>
public class PlayerManager
{
private readonly IPlayerDataService _playerDataService;
private readonly IGameConfigService _configService;
private readonly IAudioService _audioService;
// 构造函数注入
public PlayerManager(
IPlayerDataService playerDataService,
IGameConfigService configService,
IAudioService audioService)
{
_playerDataService = playerDataService;
_configService = configService;
_audioService = audioService;
GD.Print($"[PlayerManager] 已创建,游戏版本: {_configService.GameVersion}");
}
public void CreatePlayer(string playerId)
{
_playerDataService.LoadPlayerData(playerId);
_audioService.PlaySound("player_join");
GD.Print($"[PlayerManager] 玩家已创建: {playerId}");
}
public void RemovePlayer(string playerId)
{
_playerDataService.SavePlayerData(playerId);
_audioService.PlaySound("player_leave");
GD.Print($"[PlayerManager] 玩家已移除: {playerId}");
}
}
/// <summary>
/// 游戏管理器 - 使用字段注入
/// </summary>
public class GameManager
{
// 字段注入
[Inject]
private IGameConfigService _configService;
[Inject]
private IAudioService _audioService;
[Inject(Optional = true)]
private IPlayerDataService _playerDataService; // 可选注入
public void StartGame()
{
GD.Print($"[GameManager] 游戏启动,版本: {_configService.GameVersion}");
_audioService.PlaySound("game_start");
}
public void EndGame()
{
GD.Print("[GameManager] 游戏结束");
_audioService.PlaySound("game_over");
}
}
// ============================================
// DI配置和启动
// ============================================
public class DIExample : Node
{
private DependencyContainer _container;
public override void _Ready()
{
// 创建DI容器
_container = new DependencyContainer();
// 配置服务注册
ConfigureServices();
// 测试依赖注入
TestDependencyInjection();
// 测试作用域
TestScopedServices();
}
/// <summary>
/// 配置服务
/// </summary>
private void ConfigureServices()
{
// 注册单例服务
_container.Register<IGameConfigService, GameConfigService>(ServiceLifetime.Singleton);
// 注册瞬态服务
_container.Register<IPlayerDataService, PlayerDataService>(ServiceLifetime.Transient);
_container.Register<IAudioService, AudioService>(ServiceLifetime.Transient);
// 注册工厂方法
_container.RegisterFactory<PlayerManager>(container =>
{
var playerData = container.Resolve<IPlayerDataService>();
var config = container.Resolve<IGameConfigService>();
var audio = container.Resolve<IAudioService>();
return new PlayerManager(playerData, config, audio);
}, ServiceLifetime.Transient);
// 注册命名服务
_container.Register<IAudioService, AudioService>(ServiceLifetime.Singleton, "Music");
_container.Register<IAudioService, AudioService>(ServiceLifetime.Singleton, "SFX");
GD.Print("[DIExample] 服务配置完成");
}
/// <summary>
/// 测试依赖注入
/// </summary>
private void TestDependencyInjection()
{
GD.Print("\n=== 测试依赖注入 ===\n");
// 解析PlayerManager(使用构造函数注入)
var playerManager = _container.Resolve<PlayerManager>();
playerManager.CreatePlayer("player_001");
playerManager.RemovePlayer("player_001");
// 解析GameManager(使用字段注入)
var gameManager = new GameManager();
_container.InjectProperties(gameManager); // 手动执行属性注入
gameManager.StartGame();
gameManager.EndGame();
// 测试命名服务
var musicAudio = _container.Resolve<IAudioService>("Music");
var sfxAudio = _container.Resolve<IAudioService>("SFX");
musicAudio.SetVolume(0.5f);
sfxAudio.SetVolume(0.8f);
GD.Print($"Music和SFX是否是同一实例: {ReferenceEquals(musicAudio, sfxAudio)}");
}
/// <summary>
/// 测试作用域服务
/// </summary>
private void TestScopedServices()
{
GD.Print("\n=== 测试作用域服务 ===\n");
// 注册作用域服务
_container.Register<IPlayerDataService, PlayerDataService>(ServiceLifetime.Scoped);
// 创建作用域1
using (var scope1 = _container.CreateScope())
{
var playerService1 = scope1.Resolve<IPlayerDataService>();
playerService1.LoadPlayerData("scope_player_1");
// 在同一个作用域中解析应该得到相同实例
var playerService1Again = scope1.Resolve<IPlayerDataService>();
GD.Print($"同一作用域内实例相同: {ReferenceEquals(playerService1, playerService1Again)}");
}
// 创建作用域2
using (var scope2 = _container.CreateScope())
{
var playerService2 = scope2.Resolve<IPlayerDataService>();
playerService2.LoadPlayerData("scope_player_2");
}
}
public override void _ExitTree()
{
_container?.Dispose();
}
}
}
6.4 最佳实践
6.4.1 组件设计原则
- 单一职责原则:每个组件只负责一个明确的功能
- 组合优于继承:通过组件组合实现功能,而非深层继承
- 最小依赖:组件之间应尽量减少直接依赖
- 数据与逻辑分离:组件存储数据,系统处理逻辑(ECS模式)
6.4.2 ECS 使用建议
- 实体轻量化:实体应尽可能轻量,避免在实体类中添加过多逻辑
- 组件数据化:组件应该是纯数据结构,避免包含复杂逻辑
- 系统专注化:每个系统只处理一种特定类型的逻辑
- 合理使用查询:避免每帧遍历所有实体,使用组件过滤
6.4.3 依赖注入最佳实践
- 优先使用接口:服务应该通过接口定义,实现解耦
- 生命周期管理:正确选择服务的生命周期(Singleton/Scoped/Transient)
- 避免循环依赖:设计时注意避免服务之间的循环依赖
- 延迟解析:尽可能在构造函数中注入依赖,而非运行时解析
本章小结
本章详细介绍了 Godot C# 中组件化架构的三种实现方式:
- 传统组件模式:通过
ComponentBase基类和生命周期管理实现,适合小规模项目 - ECS 架构:提供高性能的实体-组件-系统实现,适合大规模游戏
- 依赖注入:通过 DI 容器管理服务依赖,提高代码的可测试性和可维护性
选择哪种架构模式取决于项目规模和复杂度:
- 小型项目:使用传统组件模式即可
- 中型项目:结合组件模式和 DI 容器
- 大型项目:采用完整的 ECS 架构配合 DI