Skip to content

架构概览

GFramework 采用经典的五层架构模式,结合 CQRS 和事件驱动设计,为游戏开发提供清晰、可维护的架构基础。

核心架构模式

五层架构

┌─────────────────────────────────────────┐
│             View / UI                    │  ← 用户界面层
├─────────────────────────────────────────┤
│            Controller                    │  ← 控制层
├─────────────────────────────────────────┤
│             System                       │  ← 业务逻辑层
├─────────────────────────────────────────┤
│              Model                       │  ← 数据层
├─────────────────────────────────────────┤
│             Utility                      │  ← 工具层
└─────────────────────────────────────────┘

跨层操作机制

Command ──┐
Query   ──┼──→  跨层操作(修改/查询数据)
Event   ──┘

生命周期阶段

初始化:Init → BeforeUtilityInit → AfterUtilityInit → BeforeModelInit → AfterModelInit → BeforeSystemInit → AfterSystemInit → Ready
销毁:Destroy → Destroying → Destroyed

核心组件详解

1. Architecture(架构)

应用的中央调度器,负责管理所有组件的生命周期。

csharp
public class GameArchitecture : Architecture
{
    protected override void Init()
    {
        // 注册所有组件
        RegisterModel(new PlayerModel());
        RegisterSystem(new CombatSystem());
        RegisterUtility(new StorageUtility());
    }
}

主要职责:

  • 组件注册和管理
  • 生命周期协调
  • 依赖注入
  • 跨组件通信协调

2. Model(数据模型)

应用的状态存储层,只负责数据的存储和管理。

csharp
public class PlayerModel : AbstractModel
{
    public BindableProperty<int> Health { get; } = new(100);
    public BindableProperty<string> Name { get; } = new("Player");
    
    protected override void OnInit()
    {
        // 监听自身数据变化
        Health.Register(OnHealthChanged);
    }
    
    private void OnHealthChanged(int newHealth)
    {
        if (newHealth <= 0)
            this.SendEvent(new PlayerDiedEvent());
    }
}

设计原则:

  • 只存储数据,不包含业务逻辑
  • 使用 BindableProperty 实现响应式数据
  • 通过事件通知数据变化

3. System(业务系统)

应用的业务逻辑处理层。

csharp
public class CombatSystem : AbstractSystem
{
    protected override void OnInit()
    {
// 订阅相关事件
this.GetEvent<AttackEvent>().Register(OnAttack);
}

    private void OnAttack(AttackEvent e)
    {
        var attacker = e.Attacker;
        var target = e.Target;
        
        // 计算伤害
        var damage = CalculateDamage(attacker, target);
        
        // 更新目标生命值
        target.Health.Value -= damage;
        
        // 发送伤害事件
        this.SendEvent(new DamageEvent(target, damage));
    }
    
    private int CalculateDamage(Entity attacker, Entity target)
    {
        return Mathf.Max(1, attacker.Attack.Value - target.Defense.Value);
    }
}

设计原则:

  • 处理业务逻辑,不直接存储数据
  • 通过事件与其他组件通信
  • 从 Model 获取数据,向 Model 发送更新

4. Controller(控制器)

连接 UI 和业务逻辑的桥梁。

csharp
public class PlayerController : IController
{
    private IArchitecture _architecture;
    private PlayerModel _playerModel;
    
    public PlayerController(IArchitecture architecture)
    {
        _architecture = architecture;
        _playerModel = architecture.GetModel<PlayerModel>();
        
        // 监听模型变化并更新 UI
        _playerModel.Health.RegisterWithInitValue(UpdateHealthDisplay);
    }
    
    public void OnPlayerInput(Vector2 direction)
    {
        // 将用户输入转换为命令
        _architecture.SendCommand(new MovePlayerCommand { Direction = direction });
    }
    
    private void UpdateHealthDisplay(int health)
    {
        // 更新 UI 显示
        Console.WriteLine($"Player Health: {health}");
    }
}

核心功能:

  • 接收用户输入
  • 发送命令到系统
  • 监听模型变化更新 UI
  • 协调 UI 和业务逻辑

5. Utility(工具类)

提供无状态的辅助功能。

csharp
public class StorageUtility : IUtility
{
    public void SaveData<T>(string key, T data)
    {
        // 实现数据保存逻辑
    }
    
    public T LoadData<T>(string key, T defaultValue = default)
    {
        // 实现数据加载逻辑
        return defaultValue;
    }
}

使用场景:

  • 数据存储和读取
  • 数学计算工具
  • 字符串处理
  • 网络通信辅助

通信机制

1. Command(命令)

用于修改应用状态的操作:

csharp
public class MovePlayerCommand : AbstractCommand
{
    public Vector2 Direction { get; set; }
    
    protected override void OnDo()
    {
        // 执行移动逻辑
        this.SendEvent(new PlayerMovedEvent { Position = CalculateNewPosition() });
    }
}

2. Query(查询)

用于查询应用状态:`

csharp
public class GetPlayerHealthQuery : AbstractQuery<int>
{
    protected override int OnDo()
    {
        var playerModel = this.GetModel<PlayerModel>();
        return playerModel.Health.Value;
    }
}

3. Event(事件)

组件间通信的主要机制:`

// 发送事件
this.SendEvent(new PlayerDiedEvent());

// 监听事件
this.RegisterEvent<PlayerDiedEvent>(OnPlayerDied);

响应式编程

BindableProperty

csharp
public class PlayerModel : AbstractModel
{
    public BindableProperty<int> Health { get; } = new(100);
    public BindableProperty<string> Name { get; } = new("Player");
}

// 使用方式
playerModel.Health.Value = 50; // 自动触发所有监听器
playerModel.Health.Register(newValue => {
    Console.WriteLine($"Health changed to: {newValue}");
});

数据绑定优势

  • 自动更新:数据变化自动通知监听者
  • 内存安全:自动管理监听器生命周期
  • 类型安全:编译时类型检查
  • 性能优化:只在值真正改变时触发

最佳实践

1. 分层职责明确

csharp
// ✅ 正确:Model 只存储数据
public class PlayerModel : AbstractModel
{
    public BindableProperty<int> Health { get; } = new(100);
}

// ❌ 错误:Model 包含业务逻辑
public class PlayerModel : AbstractModel
{
    public void TakeDamage(int damage) // 业务逻辑应该在 System 中
    {
        Health.Value -= damage;
    }
}

2. 事件驱动设计

csharp
// ✅ 正确:使用事件解耦
public class CombatSystem : AbstractSystem
{
    private void OnPlayerAttack(PlayerAttackEvent e)
    {
        // 处理攻击逻辑
        this.SendEvent(new EnemyDamagedEvent { Damage = CalculateDamage() });
    }
}

// ❌ 错误:直接调用其他组件
public class CombatSystem : AbstractSystem
{
    private void OnPlayerAttack(PlayerAttackEvent e)
    {
        var enemySystem = this.GetSystem<EnemySystem>(); // 紧耦合
        enemySystem.TakeDamage(CalculateDamage());
    }
}

3. 命令查询分离

csharp
// ✅ 正确:明确区分命令和查询
public class MovePlayerCommand : AbstractCommand { }  // 修改状态
public class GetPlayerPositionQuery : AbstractQuery<Vector2> { }  // 查询状态

// ❌ 错误:混合读写操作
public class PlayerManager 
{
    public void MoveAndGetPosition(Vector2 direction, out Vector2 position) // 职责不清
    {
        // ...
    }
}

架构优势

1. 可维护性

  • 清晰的职责分离
  • 松耦合的组件设计
  • 易于定位和修复问题

2. 可测试性

  • 组件可独立测试
  • 依赖可轻松模拟
  • 支持单元测试和集成测试

3. 可扩展性

  • 新功能通过添加组件实现
  • 现有组件无需修改
  • 支持插件化架构

4. 团队协作

  • 统一的架构规范
  • 易于新人上手
  • 减少代码冲突

基于 Apache 2.0 许可证发布