From f35c9309f3fa28e896a994fb8a7906d713070474 Mon Sep 17 00:00:00 2001 From: GeWuYou <95328647+GeWuYou@users.noreply.github.com> Date: Sun, 8 Mar 2026 20:55:03 +0800 Subject: [PATCH] =?UTF-8?q?docs(menu):=20=E9=87=8D=E6=9E=84=20ECS=20?= =?UTF-8?q?=E6=96=87=E6=A1=A3=E5=AF=BC=E8=88=AA=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将 ECS 相关菜单项从 Core 部分独立出来 - 新增 ECS 概述页面和 Arch ECS 集成文档 - 删除旧的 Core/ECS 集成文档文件 - 更新侧边栏配置以支持新的 ECS 导航结构 --- docs/.vitepress/config.mts | 12 +- docs/zh-CN/core/ecs.md | 1006 ------------------------------------ docs/zh-CN/ecs/arch.md | 751 +++++++++++++++++++++++++++ docs/zh-CN/ecs/index.md | 297 +++++++++++ 4 files changed, 1059 insertions(+), 1007 deletions(-) delete mode 100644 docs/zh-CN/core/ecs.md create mode 100644 docs/zh-CN/ecs/arch.md create mode 100644 docs/zh-CN/ecs/index.md diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index a6aaef0..cc889fe 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -47,6 +47,7 @@ export default defineConfig({ { text: '首页', link: '/zh-CN/' }, { text: '入门指南', link: '/zh-CN/getting-started' }, { text: 'Core', link: '/zh-CN/core/' }, + { text: 'ECS', link: '/zh-CN/ecs/' }, { text: 'Game', link: '/zh-CN/game/' }, { text: 'Godot', link: '/zh-CN/godot/' }, { text: '源码生成器', link: '/zh-CN/source-generators' }, @@ -91,7 +92,6 @@ export default defineConfig({ { text: '事件系统', link: '/zh-CN/core/events' }, { text: '属性系统', link: '/zh-CN/core/property' }, { text: 'IoC容器', link: '/zh-CN/core/ioc' }, - { text: 'ECS 系统集成', link: '/zh-CN/core/ecs' }, { text: '协程系统', link: '/zh-CN/core/coroutine' }, { text: '状态机', link: '/zh-CN/core/state-machine' }, { text: '暂停系统', link: '/zh-CN/core/pause' }, @@ -110,6 +110,16 @@ export default defineConfig({ } ], + '/zh-CN/ecs/': [ + { + text: 'ECS 系统集成', + items: [ + { text: 'ECS 概述', link: '/zh-CN/ecs/' }, + { text: 'Arch ECS 集成', link: '/zh-CN/ecs/arch' } + ] + } + ], + '/zh-CN/game/': [ { text: 'Game 游戏模块', diff --git a/docs/zh-CN/core/ecs.md b/docs/zh-CN/core/ecs.md deleted file mode 100644 index 527fa6a..0000000 --- a/docs/zh-CN/core/ecs.md +++ /dev/null @@ -1,1006 +0,0 @@ ---- -title: ECS 系统集成 -description: ECS(Entity Component System)系统集成指南,基于 Arch.Core 实现高性能的实体组件系统。 ---- - -# ECS 系统集成 - -## 概述 - -GFramework 集成了 [Arch.Core](https://github.com/genaray/Arch) ECS 框架,提供高性能的实体组件系统(Entity Component -System)架构。通过 ECS 模式,你可以构建数据驱动、高度可扩展的游戏系统。 - -**主要特性**: - -- 基于 Arch.Core 的高性能 ECS 实现 -- 与 GFramework 架构无缝集成 -- 支持组件查询和批量处理 -- 零 GC 分配的组件访问 -- 灵活的系统生命周期管理 -- 支持多线程并行处理(Arch 原生支持) - -**性能特点**: - -- 10,000 个实体更新 < 100ms -- 1,000 个实体创建 < 50ms -- 基于 Archetype 的高效内存布局 -- 支持 SIMD 优化 - -## 核心概念 - -### Entity(实体) - -实体是游戏世界中的基本对象,本质上是一个唯一标识符(ID)。实体本身不包含数据或逻辑,只是组件的容器。 - -```csharp -using Arch.Core; - -// 创建实体 -var entity = world.Create(); - -// 创建带组件的实体 -var entity = world.Create(new Position(0, 0), new Velocity(1, 1)); -``` - -### Component(组件) - -组件是纯数据结构,用于存储实体的状态。组件应该是简单的值类型(struct),不包含逻辑。 - -```csharp -using System.Runtime.InteropServices; - -/// -/// 位置组件 -/// -[StructLayout(LayoutKind.Sequential)] -public struct Position(float x, float y) -{ - public float X { get; set; } = x; - public float Y { get; set; } = y; -} - -/// -/// 速度组件 -/// -[StructLayout(LayoutKind.Sequential)] -public struct Velocity(float x, float y) -{ - public float X { get; set; } = x; - public float Y { get; set; } = y; -} -``` - -**组件设计原则**: - -- 使用 `struct` 而不是 `class` -- 只包含数据,不包含逻辑 -- 使用 `[StructLayout(LayoutKind.Sequential)]` 优化内存布局 -- 保持组件小而专注 - -### System(系统) - -系统包含游戏逻辑,负责处理具有特定组件组合的实体。在 GFramework 中,系统通过继承 `ArchSystemAdapter<T>` 来实现。 - -```csharp -using Arch.Core; -using GFramework.Core.ecs; - -/// -/// 移动系统 - 更新实体位置 -/// -public sealed class MovementSystem : ArchSystemAdapter -{ - private QueryDescription _query; - - protected override void OnArchInitialize() - { - // 创建查询:查找所有同时拥有 Position 和 Velocity 组件的实体 - _query = new QueryDescription() - .WithAll(); - } - - protected override void OnUpdate(in float deltaTime) - { - // 查询并更新所有符合条件的实体 - World.Query(in _query, (ref Position pos, ref Velocity vel) => - { - pos.X += vel.X * deltaTime; - pos.Y += vel.Y * deltaTime; - }); - } -} -``` - -### World(世界) - -World 是 ECS 的核心容器,管理所有实体和组件。GFramework 通过 `ArchEcsModule` 自动创建和管理 World。 - -```csharp -// World 由 ArchEcsModule 自动创建和注册到 IoC 容器 -// 在系统中可以直接访问 -public class MySystem : ArchSystemAdapter -{ - protected override void OnUpdate(in float deltaTime) - { - // 访问 World - var entityCount = World.Size; - } -} -``` - -### Arch.Core 集成 - -GFramework 通过以下组件桥接 Arch.Core 到框架生命周期: - -- **ArchEcsModule**:ECS 模块,管理 World 和系统生命周期 -- **ArchSystemAdapter<T>**:系统适配器,桥接 Arch 系统到 GFramework - -## 基本用法 - -### 1. 定义组件 - -```csharp -using System.Runtime.InteropServices; - -namespace MyGame.Components; - -[StructLayout(LayoutKind.Sequential)] -public struct Health(float current, float max) -{ - public float Current { get; set; } = current; - public float Max { get; set; } = max; -} - -[StructLayout(LayoutKind.Sequential)] -public struct Damage(float value) -{ - public float Value { get; set; } = value; -} - -[StructLayout(LayoutKind.Sequential)] -public struct PlayerTag -{ - // 标签组件,不需要数据 -} -``` - -### 2. 创建系统 - -```csharp -using Arch.Core; -using GFramework.Core.ecs; -using MyGame.Components; - -namespace MyGame.Systems; - -/// -/// 伤害系统 - 处理伤害逻辑 -/// -public sealed class DamageSystem : ArchSystemAdapter -{ - private QueryDescription _query; - - protected override void OnArchInitialize() - { - // 查询所有具有 Health 和 Damage 组件的实体 - _query = new QueryDescription() - .WithAll(); - } - - protected override void OnUpdate(in float deltaTime) - { - // 处理伤害 - World.Query(in _query, (Entity entity, ref Health health, ref Damage damage) => - { - health.Current -= damage.Value * deltaTime; - - // 如果生命值耗尽,移除伤害组件 - if (health.Current <= 0) - { - health.Current = 0; - World.Remove(entity); - } - }); - } -} -``` - -### 3. 注册 ECS 模块 - -```csharp -using GFramework.Core.architecture; -using GFramework.Core.ecs; -using MyGame.Systems; - -public class GameArchitecture : Architecture -{ - protected override void Init() - { - // 注册 ECS 系统 - RegisterSystem(new MovementSystem()); - RegisterSystem(new DamageSystem()); - - // 安装 ECS 模块 - InstallModule(new ArchEcsModule(enabled: true)); - } -} -``` - -### 4. 创建和管理实体 - -```csharp -using Arch.Core; -using GFramework.Core.Abstractions.controller; -using MyGame.Components; -using GFramework.Core.Abstractions.controller; -using GFramework.SourceGenerators.Abstractions.rule; - -[ContextAware] -public partial class GameController : IController -{ - private World _world; - - public void Start() - { - // 获取 World - _world = this.GetService(); - - // 创建玩家实体 - var player = _world.Create( - new Position(0, 0), - new Velocity(0, 0), - new Health(100, 100), - new PlayerTag() - ); - - // 创建敌人实体 - var enemy = _world.Create( - new Position(10, 10), - new Velocity(-1, 0), - new Health(50, 50) - ); - } - - public void ApplyDamage(Entity entity, float damageValue) - { - // 添加伤害组件 - if (_world.Has(entity)) - { - _world.Add(entity, new Damage(damageValue)); - } - } -} -``` - -### 5. 更新 ECS 系统 - -```csharp -// 在游戏主循环中更新 ECS -public class GameLoop -{ - private ArchEcsModule _ecsModule; - - public void Update(float deltaTime) - { - // 更新所有 ECS 系统 - _ecsModule.Update(deltaTime); - } -} -``` - -## 高级用法 - -### 查询实体 - -Arch 提供了强大的查询 API,支持多种过滤条件: - -```csharp -using Arch.Core; - -public class QueryExampleSystem : ArchSystemAdapter -{ - private QueryDescription _query1; - private QueryDescription _query2; - private QueryDescription _query3; - - protected override void OnArchInitialize() - { - // 查询:必须有 Position 和 Velocity - _query1 = new QueryDescription() - .WithAll(); - - // 查询:必须有 Health,但不能有 Damage - _query2 = new QueryDescription() - .WithAll() - .WithNone(); - - // 查询:必须有 Position,可选 Velocity - _query3 = new QueryDescription() - .WithAll() - .WithAny(); - } - - protected override void OnUpdate(in float deltaTime) - { - // 使用查询 1 - World.Query(in _query1, (ref Position pos, ref Velocity vel) => - { - // 处理逻辑 - }); - - // 使用查询 2 - World.Query(in _query2, (Entity entity, ref Health health) => - { - // 处理逻辑 - }); - } -} -``` - -### 系统生命周期钩子 - -`ArchSystemAdapter<T>` 提供了多个生命周期钩子: - -```csharp -public class LifecycleExampleSystem : ArchSystemAdapter -{ - protected override void OnArchInitialize() - { - // Arch 系统初始化 - // 在这里创建查询、初始化资源 - } - - protected override void OnBeforeUpdate(in float deltaTime) - { - // 更新前调用 - // 可用于预处理逻辑 - } - - protected override void OnUpdate(in float deltaTime) - { - // 主更新逻辑 - } - - protected override void OnAfterUpdate(in float deltaTime) - { - // 更新后调用 - // 可用于后处理逻辑 - } - - protected override void OnArchDispose() - { - // 资源清理 - } -} -``` - -### 组件操作 - -```csharp -using Arch.Core; - -public class ComponentOperations -{ - private World _world; - - public void Examples() - { - var entity = _world.Create(); - - // 添加组件 - _world.Add(entity, new Position(0, 0)); - _world.Add(entity, new Velocity(1, 1)); - - // 检查组件 - if (_world.Has(entity)) - { - // 获取组件引用(零 GC 分配) - ref var pos = ref _world.Get(entity); - pos.X += 10; - } - - // 设置组件(替换现有值) - _world.Set(entity, new Position(100, 100)); - - // 移除组件 - _world.Remove(entity); - - // 销毁实体 - _world.Destroy(entity); - } -} -``` - -### 批量操作 - -```csharp -public class BatchOperations -{ - private World _world; - - public void CreateMultipleEntities() - { - // 批量创建实体 - for (int i = 0; i < 1000; i++) - { - _world.Create( - new Position(i, i), - new Velocity(1, 1) - ); - } - } - - public void ClearAllEntities() - { - // 清空所有实体 - _world.Clear(); - } -} -``` - -### 实体查询和迭代 - -```csharp -public class EntityIterationSystem : ArchSystemAdapter -{ - protected override void OnUpdate(in float deltaTime) - { - // 方式 1:使用查询和 Lambda - var query = new QueryDescription().WithAll(); - World.Query(in query, (ref Position pos) => - { - // 处理每个实体 - }); - - // 方式 2:获取实体引用 - World.Query(in query, (Entity entity, ref Position pos) => - { - // 可以访问实体 ID - if (pos.X > 100) - { - World.Destroy(entity); - } - }); - - // 方式 3:多组件查询 - var multiQuery = new QueryDescription() - .WithAll(); - - World.Query(in multiQuery, ( - Entity entity, - ref Position pos, - ref Velocity vel, - ref Health health) => - { - // 处理多个组件 - }); - } -} -``` - -## 性能优化 - -### 1. 使用 struct 组件 - -```csharp -// ✅ 推荐:使用 struct -[StructLayout(LayoutKind.Sequential)] -public struct Position(float x, float y) -{ - public float X { get; set; } = x; - public float Y { get; set; } = y; -} - -// ❌ 不推荐:使用 class -public class Position -{ - public float X { get; set; } - public float Y { get; set; } -} -``` - -### 2. 缓存查询 - -```csharp -public class OptimizedSystem : ArchSystemAdapter -{ - // ✅ 推荐:缓存查询 - private QueryDescription _cachedQuery; - - protected override void OnArchInitialize() - { - _cachedQuery = new QueryDescription() - .WithAll(); - } - - protected override void OnUpdate(in float deltaTime) - { - // 使用缓存的查询 - World.Query(in _cachedQuery, (ref Position pos, ref Velocity vel) => - { - pos.X += vel.X * deltaTime; - pos.Y += vel.Y * deltaTime; - }); - } -} - -// ❌ 不推荐:每次创建新查询 -public class UnoptimizedSystem : ArchSystemAdapter -{ - protected override void OnUpdate(in float deltaTime) - { - // 每帧创建新查询(性能差) - var query = new QueryDescription().WithAll(); - World.Query(in query, (ref Position pos, ref Velocity vel) => - { - // ... - }); - } -} -``` - -### 3. 使用 ref 访问组件 - -```csharp -// ✅ 推荐:使用 ref 避免复制 -World.Query(in query, (ref Position pos, ref Velocity vel) => -{ - pos.X += vel.X; // 直接修改,零 GC -}); - -// ❌ 不推荐:不使用 ref -World.Query(in query, (Position pos, Velocity vel) => -{ - pos.X += vel.X; // 复制值,修改不会生效 -}); -``` - -### 4. 组件大小优化 - -```csharp -// ✅ 推荐:小而专注的组件 -public struct Position(float x, float y) -{ - public float X { get; set; } = x; - public float Y { get; set; } = y; -} - -public struct Velocity(float x, float y) -{ - public float X { get; set; } = x; - public float Y { get; set; } = y; -} - -// ❌ 不推荐:大而全的组件 -public struct Transform -{ - public float X, Y, Z; - public float RotationX, RotationY, RotationZ; - public float ScaleX, ScaleY, ScaleZ; - public float VelocityX, VelocityY, VelocityZ; - // ... 太多数据 -} -``` - -### 5. 批量处理 - -```csharp -public class BatchProcessingSystem : ArchSystemAdapter -{ - protected override void OnUpdate(in float deltaTime) - { - // ✅ 推荐:批量处理 - var query = new QueryDescription().WithAll(); - World.Query(in query, (ref Position pos, ref Velocity vel) => - { - // 一次查询处理所有实体 - pos.X += vel.X * deltaTime; - pos.Y += vel.Y * deltaTime; - }); - } -} - -// ❌ 不推荐:逐个处理 -public class IndividualProcessingSystem : ArchSystemAdapter -{ - private List _entities = new(); - - protected override void OnUpdate(in float deltaTime) - { - foreach (var entity in _entities) - { - ref var pos = ref World.Get(entity); - ref var vel = ref World.Get(entity); - pos.X += vel.X * deltaTime; - pos.Y += vel.Y * deltaTime; - } - } -} -``` - -## 最佳实践 - -### 1. ECS 设计模式 - -**组件组合优于继承**: - -```csharp -// ✅ 推荐:使用组件组合 -var player = world.Create( - new Position(0, 0), - new Velocity(0, 0), - new Health(100, 100), - new PlayerTag(), - new Controllable() -); - -var enemy = world.Create( - new Position(10, 10), - new Velocity(-1, 0), - new Health(50, 50), - new EnemyTag(), - new AI() -); - -// ❌ 不推荐:使用继承 -public class Player : Entity { } -public class Enemy : Entity { } -``` - -**单一职责系统**: - -```csharp -// ✅ 推荐:每个系统只负责一件事 -public class MovementSystem : ArchSystemAdapter -{ - // 只负责移动 -} - -public class CollisionSystem : ArchSystemAdapter -{ - // 只负责碰撞检测 -} - -public class DamageSystem : ArchSystemAdapter -{ - // 只负责伤害处理 -} - -// ❌ 不推荐:一个系统做太多事 -public class GameplaySystem : ArchSystemAdapter -{ - // 移动、碰撞、伤害、AI... 太多职责 -} -``` - -### 2. 与传统架构结合 - -ECS 可以与 GFramework 的传统架构(Model、System、Utility)结合使用: - -```csharp -// Model 存储全局状态 -public class GameStateModel : AbstractModel -{ - public int Score { get; set; } - public int Level { get; set; } -} - -// ECS System 处理实体逻辑 -public class EnemySpawnSystem : ArchSystemAdapter -{ - private float _spawnTimer; - - protected override void OnUpdate(in float deltaTime) - { - _spawnTimer += deltaTime; - - if (_spawnTimer >= 2.0f) - { - // 获取 Model - var gameState = this.GetModel(); - - // 根据关卡生成敌人 - var enemyCount = gameState.Level * 2; - for (int i = 0; i < enemyCount; i++) - { - World.Create( - new Position(Random.Shared.Next(0, 100), 0), - new Velocity(0, -1), - new Health(50, 50), - new EnemyTag() - ); - } - - _spawnTimer = 0; - } - } -} - -// 传统 System 处理游戏逻辑 -public class ScoreSystem : AbstractSystem -{ - protected override void OnInit() - { - // 监听敌人死亡事件 - this.RegisterEvent(OnEnemyDestroyed); - } - - private void OnEnemyDestroyed(EnemyDestroyedEvent e) - { - var gameState = this.GetModel(); - gameState.Score += 100; - } -} -``` - -### 3. 事件集成 - -ECS 系统可以发送和接收框架事件: - -```csharp -// 定义事件 -public struct EnemyDestroyedEvent -{ - public Entity Enemy { get; init; } - public int Score { get; init; } -} - -// ECS 系统发送事件 -public class HealthSystem : ArchSystemAdapter -{ - protected override void OnUpdate(in float deltaTime) - { - var query = new QueryDescription() - .WithAll(); - - World.Query(in query, (Entity entity, ref Health health) => - { - if (health.Current <= 0) - { - // 发送事件 - this.SendEvent(new EnemyDestroyedEvent - { - Enemy = entity, - Score = 100 - }); - - // 销毁实体 - World.Destroy(entity); - } - }); - } -} - -// 传统系统接收事件 -public class UISystem : AbstractSystem -{ - protected override void OnInit() - { - this.RegisterEvent(OnEnemyDestroyed); - } - - private void OnEnemyDestroyed(EnemyDestroyedEvent e) - { - // 更新 UI - Console.WriteLine($"Enemy destroyed! +{e.Score} points"); - } -} -``` - -### 4. 标签组件 - -使用空结构体作为标签来分类实体: - -```csharp -// 定义标签组件 -public struct PlayerTag { } -public struct EnemyTag { } -public struct BulletTag { } -public struct DeadTag { } - -// 使用标签过滤实体 -public class PlayerMovementSystem : ArchSystemAdapter -{ - private QueryDescription _query; - - protected override void OnArchInitialize() - { - // 只处理玩家实体 - _query = new QueryDescription() - .WithAll() - .WithNone(); - } - - protected override void OnUpdate(in float deltaTime) - { - World.Query(in _query, (ref Position pos, ref Velocity vel) => - { - // 只更新活着的玩家 - pos.X += vel.X * deltaTime; - pos.Y += vel.Y * deltaTime; - }); - } -} -``` - -### 5. 组件生命周期管理 - -```csharp -public class LifecycleManagementSystem : ArchSystemAdapter -{ - protected override void OnUpdate(in float deltaTime) - { - // 处理临时效果 - var buffQuery = new QueryDescription().WithAll(); - World.Query(in buffQuery, (Entity entity, ref BuffComponent buff) => - { - buff.Duration -= deltaTime; - - if (buff.Duration <= 0) - { - // 移除过期的 Buff - World.Remove(entity); - } - }); - - // 清理死亡实体 - var deadQuery = new QueryDescription().WithAll(); - World.Query(in deadQuery, (Entity entity) => - { - World.Destroy(entity); - }); - } -} -``` - -## 常见问题 - -### Q: 如何在 ECS 系统中访问其他服务? - -A: `ArchSystemAdapter<T>` 继承自 `AbstractSystem`,可以使用所有 GFramework 的扩展方法: - -```csharp -public class ServiceAccessSystem : ArchSystemAdapter -{ - protected override void OnUpdate(in float deltaTime) - { - // 获取 Model - var playerModel = this.GetModel(); - - // 获取 Utility - var timeUtility = this.GetUtility(); - - // 发送命令 - this.SendCommand(new SaveGameCommand()); - - // 发送查询 - var score = this.SendQuery(new GetScoreQuery()); - - // 发送事件 - this.SendEvent(new GameOverEvent()); - } -} -``` - -### Q: ECS 和传统架构如何选择? - -A: 根据场景选择: - -- **使用 ECS**:大量相似实体、需要高性能批量处理(敌人、子弹、粒子) -- **使用传统架构**:全局状态、单例服务、UI 逻辑、游戏流程控制 - -### Q: 如何调试 ECS 系统? - -A: 使用以下方法: - -```csharp -public class DebugSystem : ArchSystemAdapter -{ - protected override void OnUpdate(in float deltaTime) - { - // 打印实体数量 - Console.WriteLine($"Total entities: {World.Size}"); - - // 查询特定实体 - var query = new QueryDescription().WithAll(); - var count = 0; - World.Query(in query, (Entity entity, ref Position pos) => - { - count++; - Console.WriteLine($"Entity {entity.Id}: ({pos.X}, {pos.Y})"); - }); - - Console.WriteLine($"Entities with Position: {count}"); - } -} -``` - -### Q: 如何处理实体之间的交互? - -A: 使用查询和事件: - -```csharp -public class CollisionSystem : ArchSystemAdapter -{ - protected override void OnUpdate(in float deltaTime) - { - var playerQuery = new QueryDescription() - .WithAll(); - var enemyQuery = new QueryDescription() - .WithAll(); - - // 检测玩家和敌人的碰撞 - World.Query(in playerQuery, (Entity player, ref Position playerPos) => - { - World.Query(in enemyQuery, (Entity enemy, ref Position enemyPos) => - { - var distance = Math.Sqrt( - Math.Pow(playerPos.X - enemyPos.X, 2) + - Math.Pow(playerPos.Y - enemyPos.Y, 2) - ); - - if (distance < 1.0f) - { - // 发送碰撞事件 - this.SendEvent(new CollisionEvent - { - Entity1 = player, - Entity2 = enemy - }); - } - }); - }); - } -} -``` - -### Q: 如何优化大量实体的性能? - -A: 参考性能优化章节,主要策略: - -1. 使用 struct 组件 -2. 缓存查询 -3. 使用 ref 访问组件 -4. 批量处理 -5. 合理设计组件大小 -6. 使用 Arch 的并行查询(高级特性) - -### Q: 可以在运行时动态添加/移除组件吗? - -A: 可以,Arch 支持运行时修改实体的组件: - -```csharp -public class DynamicComponentSystem : ArchSystemAdapter -{ - protected override void OnUpdate(in float deltaTime) - { - var query = new QueryDescription().WithAll(); - - World.Query(in query, (Entity entity, ref Position pos) => - { - // 动态添加组件 - if (pos.X > 100 && !World.Has(entity)) - { - World.Add(entity, new FastTag()); - } - - // 动态移除组件 - if (pos.X < 0 && World.Has(entity)) - { - World.Remove(entity); - } - }); - } -} -``` - -## 相关资源 - -- [Arch.Core 官方文档](https://github.com/genaray/Arch) -- [Architecture 包使用说明](./architecture.md) -- [System 包使用说明](./system.md) -- [事件系统](./events.md) - ---- - -**许可证**:Apache 2.0 diff --git a/docs/zh-CN/ecs/arch.md b/docs/zh-CN/ecs/arch.md new file mode 100644 index 0000000..19a1441 --- /dev/null +++ b/docs/zh-CN/ecs/arch.md @@ -0,0 +1,751 @@ +--- +title: Arch ECS 集成 +description: GFramework 的 Arch ECS 集成包使用指南,提供高性能的实体组件系统支持。 +--- + +# Arch ECS 集成 + +## 概述 + +`GFramework.Ecs.Arch` 是 GFramework 的 Arch ECS 集成包,提供开箱即用的 ECS(Entity Component +System)支持。基于 [Arch.Core](https://github.com/genaray/Arch) 实现,具有极致的性能和简洁的 API。 + +**主要特性**: + +- 🎯 **显式集成** - 符合 .NET 生态习惯的显式注册方式 +- 🔌 **零依赖** - 不使用时,Core 包无 Arch 依赖 +- 🎯 **类型安全** - 完整的类型系统和编译时检查 +- ⚡ **高性能** - 基于 Arch ECS 的高性能实现 +- 🔧 **易扩展** - 简单的系统适配器模式 +- 📊 **优先级支持** - 系统按优先级顺序执行 + +**性能特点**: + +- 10,000 个实体更新 < 100ms +- 1,000 个实体创建 < 50ms +- 基于 Archetype 的高效内存布局 +- 零 GC 分配的组件访问 + +## 安装 + +```bash +dotnet add package GeWuYou.GFramework.Ecs.Arch +``` + +## 快速开始 + +### 1. 注册 ECS 模块 + +```csharp +using GFramework.Core.architecture; +using GFramework.Ecs.Arch.extensions; + +public class GameArchitecture : Architecture +{ + public GameArchitecture() : base(new ArchitectureConfiguration()) + { + } + + protected override void OnInitialize() + { + // 显式注册 Arch ECS 模块 + this.UseArch(); + } +} + +// 初始化架构 +var architecture = new GameArchitecture(); +architecture.Initialize(); +``` + +### 2. 带配置的注册 + +```csharp +public class GameArchitecture : Architecture +{ + protected override void OnInitialize() + { + // 带配置的注册 + this.UseArch(options => + { + options.WorldCapacity = 2000; // World 初始容量 + options.EnableStatistics = true; // 启用统计信息 + options.Priority = 50; // 模块优先级 + }); + } +} +``` + +### 3. 定义组件 + +组件是纯数据结构,使用 `struct` 定义: + +```csharp +using System.Runtime.InteropServices; + +namespace MyGame.Components; + +[StructLayout(LayoutKind.Sequential)] +public struct Position(float x, float y) +{ + public float X { get; set; } = x; + public float Y { get; set; } = y; +} + +[StructLayout(LayoutKind.Sequential)] +public struct Velocity(float x, float y) +{ + public float X { get; set; } = x; + public float Y { get; set; } = y; +} + +[StructLayout(LayoutKind.Sequential)] +public struct Health(float current, float max) +{ + public float Current { get; set; } = current; + public float Max { get; set; } = max; +} +``` + +### 4. 创建系统 + +系统继承自 `ArchSystemAdapter`: + +```csharp +using Arch.Core; +using GFramework.Ecs.Arch; +using MyGame.Components; + +namespace MyGame.Systems; + +/// +/// 移动系统 - 更新实体位置 +/// +public sealed class MovementSystem : ArchSystemAdapter +{ + private QueryDescription _query; + + protected override void OnArchInitialize() + { + // 创建查询:查找所有同时拥有 Position 和 Velocity 组件的实体 + _query = new QueryDescription() + .WithAll(); + } + + protected override void OnUpdate(in float deltaTime) + { + // 查询并更新所有符合条件的实体 + World.Query(in _query, (ref Position pos, ref Velocity vel) => + { + pos.X += vel.X * deltaTime; + pos.Y += vel.Y * deltaTime; + }); + } +} +``` + +### 5. 注册系统 + +```csharp +public class GameArchitecture : Architecture +{ + protected override void OnInitialize() + { + this.UseArch(); + + // 注册 ECS 系统 + RegisterSystem(); + } +} +``` + +### 6. 创建实体 + +```csharp +using Arch.Core; +using GFramework.Core.Abstractions.rule; +using GFramework.SourceGenerators.Abstractions.rule; +using MyGame.Components; + +[ContextAware] +public partial class GameController +{ + public void Start() + { + // 获取 World + var world = this.GetService(); + + // 创建实体 + var player = world.Create( + new Position(0, 0), + new Velocity(0, 0), + new Health(100, 100) + ); + + var enemy = world.Create( + new Position(10, 10), + new Velocity(-1, 0), + new Health(50, 50) + ); + } +} +``` + +### 7. 更新系统 + +```csharp +using GFramework.Ecs.Arch.Abstractions; + +public class GameLoop +{ + private IArchEcsModule _ecsModule; + + public void Initialize() + { + // 获取 ECS 模块 + _ecsModule = architecture.Context.GetService(); + } + + public void Update(float deltaTime) + { + // 更新所有 ECS 系统 + _ecsModule.Update(deltaTime); + } +} +``` + +## 配置选项 + +### ArchOptions + +```csharp +public sealed class ArchOptions +{ + /// + /// World 初始容量(默认:1000) + /// + public int WorldCapacity { get; set; } = 1000; + + /// + /// 是否启用统计信息(默认:false) + /// + public bool EnableStatistics { get; set; } = false; + + /// + /// 模块优先级(默认:50) + /// + public int Priority { get; set; } = 50; +} +``` + +### 配置示例 + +```csharp +this.UseArch(options => +{ + // 设置 World 初始容量 + // 根据预期实体数量设置,避免频繁扩容 + options.WorldCapacity = 2000; + + // 启用统计信息(开发/调试时使用) + options.EnableStatistics = true; + + // 设置模块优先级 + // 数值越小,优先级越高 + options.Priority = 50; +}); +``` + +## 核心概念 + +### Entity(实体) + +实体是游戏世界中的基本对象,本质上是一个唯一标识符: + +```csharp +// 创建空实体 +var entity = world.Create(); + +// 创建带组件的实体 +var entity = world.Create( + new Position(0, 0), + new Velocity(1, 1) +); + +// 销毁实体 +world.Destroy(entity); +``` + +### Component(组件) + +组件是纯数据结构,用于存储实体的状态: + +```csharp +// 添加组件 +world.Add(entity, new Position(0, 0)); + +// 检查组件 +if (world.Has(entity)) +{ + // 获取组件引用(零 GC 分配) + ref var pos = ref world.Get(entity); + pos.X += 10; +} + +// 设置组件(替换现有值) +world.Set(entity, new Position(100, 100)); + +// 移除组件 +world.Remove(entity); +``` + +### System(系统) + +系统包含游戏逻辑,处理具有特定组件组合的实体: + +```csharp +public sealed class DamageSystem : ArchSystemAdapter +{ + private QueryDescription _query; + + protected override void OnArchInitialize() + { + // 初始化查询 + _query = new QueryDescription() + .WithAll(); + } + + protected override void OnUpdate(in float deltaTime) + { + // 处理伤害 + World.Query(in _query, (Entity entity, ref Health health, ref Damage damage) => + { + health.Current -= damage.Value * deltaTime; + + if (health.Current <= 0) + { + health.Current = 0; + World.Remove(entity); + } + }); + } +} +``` + +### World(世界) + +World 是 ECS 的核心容器,管理所有实体和组件: + +```csharp +// World 由 ArchEcsModule 自动创建和注册 +var world = this.GetService(); + +// 获取实体数量 +var entityCount = world.Size; + +// 清空所有实体 +world.Clear(); +``` + +## 系统适配器 + +### ArchSystemAdapter + +`ArchSystemAdapter` 桥接 Arch.System.ISystem 到 GFramework 架构: + +```csharp +public sealed class MySystem : ArchSystemAdapter +{ + // Arch 系统初始化 + protected override void OnArchInitialize() + { + // 创建查询、初始化资源 + } + + // 更新前调用 + protected override void OnBeforeUpdate(in float deltaTime) + { + // 预处理逻辑 + } + + // 主更新逻辑 + protected override void OnUpdate(in float deltaTime) + { + // 处理实体 + } + + // 更新后调用 + protected override void OnAfterUpdate(in float deltaTime) + { + // 后处理逻辑 + } + + // 资源清理 + protected override void OnArchDispose() + { + // 清理资源 + } +} +``` + +### 访问 World + +在系统中可以直接访问 `World` 属性: + +```csharp +public sealed class MySystem : ArchSystemAdapter +{ + protected override void OnUpdate(in float deltaTime) + { + // 访问 World + var entityCount = World.Size; + + // 创建实体 + var entity = World.Create(new Position(0, 0)); + + // 查询实体 + var query = new QueryDescription().WithAll(); + World.Query(in query, (ref Position pos) => + { + // 处理逻辑 + }); + } +} +``` + +### 访问框架服务 + +`ArchSystemAdapter` 继承自 `AbstractSystem`,可以使用所有 GFramework 的扩展方法: + +```csharp +public sealed class ServiceAccessSystem : ArchSystemAdapter +{ + protected override void OnUpdate(in float deltaTime) + { + // 获取 Model + var playerModel = this.GetModel(); + + // 获取 Utility + var timeUtility = this.GetUtility(); + + // 发送命令 + this.SendCommand(new SaveGameCommand()); + + // 发送查询 + var score = this.SendQuery(new GetScoreQuery()); + + // 发送事件 + this.SendEvent(new GameOverEvent()); + } +} +``` + +## 查询实体 + +### 基本查询 + +```csharp +// 查询:必须有 Position 和 Velocity +var query = new QueryDescription() + .WithAll(); + +World.Query(in query, (ref Position pos, ref Velocity vel) => +{ + pos.X += vel.X * deltaTime; + pos.Y += vel.Y * deltaTime; +}); +``` + +### 过滤查询 + +```csharp +// 查询:必须有 Health,但不能有 Damage +var query = new QueryDescription() + .WithAll() + .WithNone(); + +World.Query(in query, (ref Health health) => +{ + // 只处理没有受伤的实体 +}); +``` + +### 可选组件查询 + +```csharp +// 查询:必须有 Position,可选 Velocity +var query = new QueryDescription() + .WithAll() + .WithAny(); + +World.Query(in query, (Entity entity, ref Position pos) => +{ + // 处理逻辑 +}); +``` + +### 访问实体 ID + +```csharp +var query = new QueryDescription().WithAll(); + +World.Query(in query, (Entity entity, ref Position pos) => +{ + // 可以访问实体 ID + Console.WriteLine($"Entity {entity.Id}: ({pos.X}, {pos.Y})"); + + // 可以对实体进行操作 + if (pos.X > 100) + { + World.Destroy(entity); + } +}); +``` + +## 系统优先级 + +系统按照优先级顺序执行,数值越小优先级越高: + +```csharp +using GFramework.Core.Abstractions.bases; +using GFramework.SourceGenerators.Abstractions.bases; + +// 使用 Priority 特性设置优先级 +[Priority(10)] // 高优先级,先执行 +public sealed class InputSystem : ArchSystemAdapter +{ + // ... +} + +[Priority(20)] // 中优先级 +public sealed class MovementSystem : ArchSystemAdapter +{ + // ... +} + +[Priority(30)] // 低优先级,后执行 +public sealed class RenderSystem : ArchSystemAdapter +{ + // ... +} +``` + +执行顺序:InputSystem → MovementSystem → RenderSystem + +## 性能优化 + +### 1. 使用 struct 组件 + +```csharp +// ✅ 推荐:使用 struct +[StructLayout(LayoutKind.Sequential)] +public struct Position(float x, float y) +{ + public float X { get; set; } = x; + public float Y { get; set; } = y; +} + +// ❌ 不推荐:使用 class +public class Position +{ + public float X { get; set; } + public float Y { get; set; } +} +``` + +### 2. 缓存查询 + +```csharp +public class OptimizedSystem : ArchSystemAdapter +{ + // ✅ 推荐:缓存查询 + private QueryDescription _cachedQuery; + + protected override void OnArchInitialize() + { + _cachedQuery = new QueryDescription() + .WithAll(); + } + + protected override void OnUpdate(in float deltaTime) + { + World.Query(in _cachedQuery, (ref Position pos, ref Velocity vel) => + { + pos.X += vel.X * deltaTime; + pos.Y += vel.Y * deltaTime; + }); + } +} +``` + +### 3. 使用 ref 访问组件 + +```csharp +// ✅ 推荐:使用 ref 避免复制 +World.Query(in query, (ref Position pos, ref Velocity vel) => +{ + pos.X += vel.X; // 直接修改,零 GC +}); + +// ❌ 不推荐:不使用 ref +World.Query(in query, (Position pos, Velocity vel) => +{ + pos.X += vel.X; // 复制值,修改不会生效 +}); +``` + +### 4. 组件大小优化 + +```csharp +// ✅ 推荐:小而专注的组件 +public struct Position(float x, float y) +{ + public float X { get; set; } = x; + public float Y { get; set; } = y; +} + +public struct Velocity(float x, float y) +{ + public float X { get; set; } = x; + public float Y { get; set; } = y; +} + +// ❌ 不推荐:大而全的组件 +public struct Transform +{ + public float X, Y, Z; + public float RotationX, RotationY, RotationZ; + public float ScaleX, ScaleY, ScaleZ; + public float VelocityX, VelocityY, VelocityZ; + // ... 太多数据 +} +``` + +## 最佳实践 + +### 1. 组件设计原则 + +- 使用 `struct` 而不是 `class` +- 只包含数据,不包含逻辑 +- 使用 `[StructLayout(LayoutKind.Sequential)]` 优化内存布局 +- 保持组件小而专注 + +### 2. 系统设计原则 + +- 单一职责:每个系统只负责一件事 +- 缓存查询:在 `OnArchInitialize` 中创建查询 +- 使用 ref:访问组件时使用 ref 参数 +- 批量处理:一次查询处理所有实体 + +### 3. 标签组件 + +使用空结构体作为标签来分类实体: + +```csharp +// 定义标签组件 +public struct PlayerTag { } +public struct EnemyTag { } +public struct DeadTag { } + +// 使用标签过滤实体 +var query = new QueryDescription() + .WithAll() + .WithNone(); +``` + +### 4. 与传统架构结合 + +```csharp +// ECS 系统可以访问 Model +public class EnemySpawnSystem : ArchSystemAdapter +{ + protected override void OnUpdate(in float deltaTime) + { + var gameState = this.GetModel(); + + // 根据关卡生成敌人 + for (int i = 0; i < gameState.Level; i++) + { + World.Create( + new Position(Random.Shared.Next(0, 100), 0), + new Velocity(0, -1), + new Health(50, 50) + ); + } + } +} +``` + +## 常见问题 + +### Q: 如何在运行时动态添加/移除组件? + +A: Arch 支持运行时修改实体的组件: + +```csharp +// 动态添加组件 +if (pos.X > 100 && !World.Has(entity)) +{ + World.Add(entity, new FastTag()); +} + +// 动态移除组件 +if (pos.X < 0 && World.Has(entity)) +{ + World.Remove(entity); +} +``` + +### Q: 如何处理实体之间的交互? + +A: 使用嵌套查询或事件: + +```csharp +// 方式 1:嵌套查询 +World.Query(in playerQuery, (Entity player, ref Position playerPos) => +{ + World.Query(in enemyQuery, (Entity enemy, ref Position enemyPos) => + { + // 检测碰撞 + }); +}); + +// 方式 2:使用事件 +this.SendEvent(new CollisionEvent +{ + Entity1 = player, + Entity2 = enemy +}); +``` + +### Q: 如何调试 ECS 系统? + +A: 使用日志和统计信息: + +```csharp +protected override void OnUpdate(in float deltaTime) +{ + // 打印实体数量 + Console.WriteLine($"Total entities: {World.Size}"); + + // 查询特定实体 + var query = new QueryDescription().WithAll(); + var count = 0; + World.Query(in query, (Entity entity, ref Position pos) => + { + count++; + Console.WriteLine($"Entity {entity.Id}: ({pos.X}, {pos.Y})"); + }); +} +``` + +## 相关资源 + +- [Arch.Core 官方文档](https://github.com/genaray/Arch) +- [ECS 概述](./index.md) +- [ECS 最佳实践](./best-practices.md) +- [性能优化指南](./performance.md) + +--- + +**许可证**:MIT License diff --git a/docs/zh-CN/ecs/index.md b/docs/zh-CN/ecs/index.md new file mode 100644 index 0000000..63100e6 --- /dev/null +++ b/docs/zh-CN/ecs/index.md @@ -0,0 +1,297 @@ +--- +title: ECS 系统集成 +description: GFramework 的 ECS(Entity Component System)集成方案,支持多种 ECS 框架。 +--- + +# ECS 系统集成 + +## 概述 + +GFramework 提供了灵活的 ECS(Entity Component System)集成方案,允许你根据项目需求选择合适的 ECS 框架。ECS +是一种数据驱动的架构模式,特别适合处理大量相似实体的场景。 + +## 什么是 ECS? + +ECS(Entity Component System)是一种架构模式,将游戏对象分解为三个核心概念: + +- **Entity(实体)**:游戏世界中的基本对象,本质上是一个唯一标识符 +- **Component(组件)**:纯数据结构,存储实体的状态 +- **System(系统)**:包含游戏逻辑,处理具有特定组件组合的实体 + +### ECS 的优势 + +- **高性能**:数据局部性好,缓存友好 +- **可扩展**:通过组合组件轻松创建新实体类型 +- **并行处理**:系统之间相互独立,易于并行化 +- **数据驱动**:逻辑与数据分离,便于序列化和网络同步 + +### 何时使用 ECS? + +**适合使用 ECS 的场景**: + +- 大量相似实体(敌人、子弹、粒子) +- 需要高性能批量处理 +- 复杂的实体组合和变化 +- 需要并行处理的系统 + +**不适合使用 ECS 的场景**: + +- 全局状态管理 +- 单例服务 +- UI 逻辑 +- 游戏流程控制 + +## 支持的 ECS 框架 + +GFramework 采用可选集成的设计,你可以根据需求选择合适的 ECS 框架: + +### Arch ECS(推荐) + +[Arch](https://github.com/genaray/Arch) 是一个高性能的 C# ECS 框架,具有以下特点: + +- ✅ **极致性能**:基于 Archetype 的内存布局,零 GC 分配 +- ✅ **简单易用**:清晰的 API,易于上手 +- ✅ **功能完整**:支持查询、过滤、并行处理等高级特性 +- ✅ **活跃维护**:社区活跃,持续更新 + +**安装方式**: + +```bash +dotnet add package GeWuYou.GFramework.Ecs.Arch +``` + +**文档链接**:[Arch ECS 集成指南](./arch.md) + +### 其他 ECS 框架 + +GFramework 的设计允许集成其他 ECS 框架,未来可能支持: + +- **DefaultEcs**:轻量级 ECS 框架 +- **Entitas**:成熟的 ECS 框架,Unity 生态常用 +- **自定义 ECS**:你可以基于 GFramework 的模块系统实现自己的 ECS 集成 + +## 快速开始 + +### 1. 选择 ECS 框架 + +根据项目需求选择合适的 ECS 框架。对于大多数项目,我们推荐使用 Arch ECS。 + +### 2. 安装集成包 + +```bash +# 安装 Arch ECS 集成包 +dotnet add package GeWuYou.GFramework.Ecs.Arch +``` + +### 3. 注册 ECS 模块 + +```csharp +using GFramework.Core.architecture; +using GFramework.Ecs.Arc; + +public class GameArchitecture : Architecture +{ + public GameArchitecture() : base(new ArchitectureConfiguration()) + { + } + + protected override void OnInitialize() + { + // 显式注册 Arch ECS 模块 + this.UseArch(options => + { + options.WorldCapacity = 2000; + options.EnableStatistics = true; + }); + } +} +``` + +### 4. 定义组件 + +```csharp +using System.Runtime.InteropServices; + +[StructLayout(LayoutKind.Sequential)] +public struct Position(float x, float y) +{ + public float X { get; set; } = x; + public float Y { get; set; } = y; +} + +[StructLayout(LayoutKind.Sequential)] +public struct Velocity(float x, float y) +{ + public float X { get; set; } = x; + public float Y { get; set; } = y; +} +``` + +### 5. 创建系统 + +```csharp +using Arch.Core; +using GFramework.Ecs.Arch; + +public sealed class MovementSystem : ArchSystemAdapter +{ + private QueryDescription _query; + + protected override void OnArchInitialize() + { + _query = new QueryDescription() + .WithAll(); + } + + protected override void OnUpdate(in float deltaTime) + { + World.Query(in _query, (ref Position pos, ref Velocity vel) => + { + pos.X += vel.X * deltaTime; + pos.Y += vel.Y * deltaTime; + }); + } +} +``` + +### 6. 注册系统 + +```csharp +public class GameArchitecture : Architecture +{ + protected override void OnInitialize() + { + this.UseArch(); + + // 注册 ECS 系统 + RegisterSystem(); + } +} +``` + +## 设计理念 + +### 显式集成 + +GFramework 采用显式集成的设计,而不是自动注册: + +```csharp +// ✅ 显式注册 - 清晰、可控 +public class GameArchitecture : Architecture +{ + protected override void OnInitialize() + { + this.UseArch(); // 明确表示使用 Arch ECS + } +} + +// ❌ 自动注册 - 隐式、难以控制 +// 只需引入包,自动注册(不推荐) +``` + +**优势**: + +- 清晰的依赖关系 +- 更好的 IDE 支持 +- 易于测试和调试 +- 符合 .NET 生态习惯 + +### 零依赖原则 + +如果你不使用 ECS,GFramework.Core 包不会引入任何 ECS 相关的依赖: + +```xml + + + + + + + + + + +``` + +### 模块化设计 + +ECS 集成基于 GFramework 的模块系统: + +```csharp +// ECS 模块实现 IServiceModule 接口 +public sealed class ArchEcsModule : IArchEcsModule +{ + public string ModuleName => nameof(ArchEcsModule); + public int Priority => 50; + public bool IsEnabled { get; } + + public void Register(IIocContainer container) { } + public void Initialize() { } + public ValueTask DestroyAsync() { } + public void Update(float deltaTime) { } +} +``` + +## 与传统架构结合 + +ECS 可以与 GFramework 的传统架构(Model、System、Utility)无缝结合: + +```csharp +// Model 存储全局状态 +public class GameStateModel : AbstractModel +{ + public int Score { get; set; } + public int Level { get; set; } +} + +// ECS System 处理实体逻辑 +public class EnemySpawnSystem : ArchSystemAdapter +{ + protected override void OnUpdate(in float deltaTime) + { + // 访问 Model + var gameState = this.GetModel(); + + // 根据关卡生成敌人 + for (int i = 0; i < gameState.Level; i++) + { + World.Create( + new Position(Random.Shared.Next(0, 100), 0), + new Velocity(0, -1), + new Health(50, 50) + ); + } + } +} + +// 传统 System 处理游戏逻辑 +public class ScoreSystem : AbstractSystem +{ + protected override void OnInit() + { + this.RegisterEvent(OnEnemyDestroyed); + } + + private void OnEnemyDestroyed(EnemyDestroyedEvent e) + { + var gameState = this.GetModel(); + gameState.Score += 100; + } +} +``` + +## 下一步 + +- [Arch ECS 集成指南](./arch.md) - 详细的 Arch ECS 使用文档 +- [ECS 最佳实践](./best-practices.md) - ECS 设计模式和优化技巧 +- [性能优化](./performance.md) - ECS 性能优化指南 + +## 相关资源 + +- [Architecture 架构系统](../core/architecture.md) +- [System 系统](../core/system.md) +- [事件系统](../core/events.md) + +--- + +**许可证**:MIT License