diff --git a/GFramework.Ecs.Arch.Abstractions/README.md b/GFramework.Ecs.Arch.Abstractions/README.md index d79bdf80..758868b9 100644 --- a/GFramework.Ecs.Arch.Abstractions/README.md +++ b/GFramework.Ecs.Arch.Abstractions/README.md @@ -33,6 +33,16 @@ | `IArchSystemAdapter.cs` | 让 ECS 系统适配到 GFramework `ISystem` 生命周期的接口 | | `ArchOptions.cs` | `WorldCapacity`、`EnableStatistics`、`Priority` 等配置对象 | +## XML 阅读基线 + +下表记录当前契约包的类型声明级 XML 基线,方便把 README、站内抽象页与源码阅读顺序对齐。 + +| 类型族 | 代表类型 | XML 状态 | 阅读重点 | +| --- | --- | --- | --- | +| 模块契约 | `IArchEcsModule` | 已覆盖 | 宿主循环如何统一驱动 ECS 更新 | +| 系统桥接契约 | `IArchSystemAdapter` | 已覆盖 | 外部模块怎样只依赖更新接口而不绑定默认实现 | +| 配置对象 | `ArchOptions` | 已覆盖 | 跨程序集共享 ECS 配置边界 | + ## 最小接入路径 ### 1. 只想约定宿主循环与 ECS 模块边界 diff --git a/GFramework.Ecs.Arch/README.md b/GFramework.Ecs.Arch/README.md index 96501af6..9d78666e 100644 --- a/GFramework.Ecs.Arch/README.md +++ b/GFramework.Ecs.Arch/README.md @@ -1,16 +1,30 @@ # GFramework.Ecs.Arch -GFramework 的 Arch ECS 集成包,提供开箱即用的 ECS(Entity Component System)支持。 +`GFramework.Ecs.Arch` 是 `GFramework` 当前 Arch ECS family 的默认运行时实现包。 -## 特性 +它负责把 Arch `World`、GFramework 的服务模块生命周期,以及 `ArchSystemAdapter` 系统桥接到同一条采用路径中。 +如果你需要的只是共享契约,请改为依赖 `GFramework.Ecs.Arch.Abstractions`。 -- 🎯 **显式集成** - 符合 .NET 生态习惯的显式注册方式 -- 🔌 **零依赖** - 不使用时,Core 包无 Arch 依赖 -- 🎯 **类型安全** - 完整的类型系统和编译时检查 -- ⚡ **高性能** - 基于 Arch ECS 的高性能实现 -- 🔧 **易扩展** - 简单的系统适配器模式 +## 包定位 -## 快速开始 +- 这是运行时实现层,不是纯契约层。 +- 适合需要 `UseArch(...)`、`World` 自动注册、默认模块生命周期和系统桥接基类的项目。 +- 常见场景: + - 在架构实例上显式接入 Arch ECS + - 让 `World` 由默认模块创建并放入容器 + - 让 ECS 系统复用 `ArchSystemAdapter` 生命周期桥接 + - 通过 `IArchEcsModule.Update(deltaTime)` 统一驱动 ECS 帧更新 + +## 与相邻包的关系 + +- `GFramework.Core` + - 提供架构、容器、生命周期和系统注册基础设施。 +- `GFramework.Ecs.Arch.Abstractions` + - 提供 `IArchEcsModule`、`IArchSystemAdapter` 和契约层 `ArchOptions`。 +- `GFramework.Ecs.Arch` + - 提供 `UseArch(...)`、默认 `ArchEcsModule`、`World` 注册,以及系统适配器基类与示例类型。 + +## 最小接入路径 ### 1. 安装包 @@ -18,53 +32,43 @@ GFramework 的 Arch ECS 集成包,提供开箱即用的 ECS(Entity Component dotnet add package GeWuYou.GFramework.Ecs.Arch ``` -### 2. 注册 ECS 模块 +### 2. 在 `Initialize()` 之前显式接入 Arch runtime + +按当前实现,`UseArch(...)` 会把 `ArchEcsModule` 提前登记到 `ArchitectureModuleRegistry`,因此调用时机应早于 +`Initialize()`。 ```csharp -// 在架构初始化时添加 Arch ECS 支持 -var architecture = new GameArchitecture(config) - .UseArch(); // 添加 ECS 支持 +using GFramework.Core.Architectures; +using GFramework.Ecs.Arch.Extensions; -architecture.Initialize(); -``` +public sealed class GameArchitecture : Architecture +{ + public GameArchitecture() : base(new ArchitectureConfiguration()) + { + } -### 3. 带配置的注册 + protected override void OnInitialize() + { + RegisterSystem(); + } +} -```csharp -var architecture = new GameArchitecture(config) +var architecture = new GameArchitecture() .UseArch(options => { - options.WorldCapacity = 2000; - options.EnableStatistics = true; + options.WorldCapacity = 2048; options.Priority = 50; }); architecture.Initialize(); ``` -```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. 创建系统 +### 3. 编写并注册系统 ```csharp using Arch.Core; using GFramework.Ecs.Arch; +using GFramework.Ecs.Arch.Components; public sealed class MovementSystem : ArchSystemAdapter { @@ -78,115 +82,57 @@ public sealed class MovementSystem : ArchSystemAdapter protected override void OnUpdate(in float deltaTime) { - World.Query(in _query, (ref Position pos, ref Velocity vel) => + var frameDelta = deltaTime; + + World.Query(in _query, (ref Position position, ref Velocity velocity) => { - pos.X += vel.X * deltaTime; - pos.Y += vel.Y * deltaTime; + position.X += velocity.X * frameDelta; + position.Y += velocity.Y * frameDelta; }); } } ``` -### 6. 注册系统 +### 4. 初始化后获取 `World` 与 ECS 模块 ```csharp -public class MyArchitecture : Architecture -{ - protected override void OnRegisterSystem(IIocContainer container) - { - container.Register(); - } -} +using Arch.Core; +using GFramework.Ecs.Arch.Abstractions; + +var world = architecture.Context.GetService(); +var ecsModule = architecture.Context.GetService(); ``` -### 7. 创建实体 +### 5. 由宿主循环驱动更新 ```csharp -var world = this.GetService(); -var entity = world.Create( - new Position(0, 0), - new Velocity(1, 1) -); -``` - -### 8. 更新系统 - -```csharp -var ecsModule = this.GetService(); ecsModule.Update(deltaTime); ``` -## 配置选项 +## 运行时职责地图 -### 代码配置 +| 文件 | 作用 | +| --- | --- | +| `Extensions/ArchExtensions.cs` | 通过 `UseArch(...)` 把默认模块注册到 `ArchitectureModuleRegistry` | +| `ArchEcsModule.cs` | 创建并注册 `World`,按优先级收集 `ArchSystemAdapter`,负责初始化、销毁和逐帧更新 | +| `ArchSystemAdapter.cs` | 把 GFramework 系统生命周期桥接到 Arch `ISystem` 生命周期 | +| `ArchOptions.cs` | 承载 `WorldCapacity`、`EnableStatistics`、`Priority` 这组运行时配置 | +| `Components/*.cs`、`Systems/*.cs` | 提供最小组件与系统示例,帮助对照查询写法和更新模式 | -```csharp -var architecture = new GameArchitecture(config) - .UseArch(options => - { - options.WorldCapacity = 2000; - options.EnableStatistics = true; - options.Priority = 50; - }); -``` +## XML 阅读基线 -### 配置说明 +下表记录当前模块 README 与源码可对照的类型声明级 XML 基线。 -- `WorldCapacity` - World 初始容量(默认:1000) -- `EnableStatistics` - 是否启用统计信息(默认:false) -- `Priority` - 模块优先级(默认:50) +| 类型族 | 代表类型 | XML 状态 | 阅读重点 | +| --- | --- | --- | --- | +| 装配入口 | `ArchExtensions` | 已覆盖 | `UseArch(...)` 的时机与返回值 | +| 运行时模块 | `ArchEcsModule` | 已覆盖 | `World` 注册、系统排序、销毁顺序 | +| 系统桥接层 | `ArchSystemAdapter` | 已覆盖 | `OnArchInitialize`、`OnUpdate`、`OnArchDispose` | +| 示例类型 | `Position`、`Velocity`、`MovementSystem` | 已覆盖 | 组件布局、查询写法、最小示例 | -## 架构说明 +## 对应文档入口 -### 显式注册模式 - -本包采用 .NET 生态标准的显式注册模式,基于架构实例: - -**优点:** - -- ✅ 符合 .NET 生态习惯 -- ✅ 显式、可控 -- ✅ 易于测试和调试 -- ✅ 支持配置 -- ✅ 支持链式调用 -- ✅ 避免"魔法"行为 - -**使用方式:** -```csharp -// 在架构初始化时添加 -var architecture = new GameArchitecture(config) - .UseArch(); // 显式注册 - -architecture.Initialize(); -``` - -详见:[INTEGRATION_PATTERN.md](INTEGRATION_PATTERN.md) - -### 系统适配器 - -`ArchSystemAdapter` 桥接 Arch.System.ISystem 到 GFramework 架构: - -- 自动获取 World 实例 -- 集成到框架生命周期 -- 支持上下文感知(Context-Aware) - -### 生命周期 - -1. **注册阶段** - 模块自动注册到架构 -2. **初始化阶段** - 创建 World,初始化系统 -3. **运行阶段** - 每帧调用 Update -4. **销毁阶段** - 清理资源,销毁 World - -## 示例 - -完整示例请参考 `GFramework.Ecs.Arch.Tests` 项目。 - -## 依赖 - -- GFramework.Core >= 1.0.0 -- Arch >= 2.1.0 -- Arch.System >= 1.1.0 - -## 许可证 - -MIT License +- ECS 总览:[`../docs/zh-CN/ecs/index.md`](../docs/zh-CN/ecs/index.md) +- Arch ECS 集成:[`../docs/zh-CN/ecs/arch.md`](../docs/zh-CN/ecs/arch.md) +- 抽象契约页:[`../docs/zh-CN/abstractions/ecs-arch-abstractions.md`](../docs/zh-CN/abstractions/ecs-arch-abstractions.md) +- 统一 API / XML 导航:[`../docs/zh-CN/api-reference/index.md`](../docs/zh-CN/api-reference/index.md) diff --git a/ai-plan/public/documentation-full-coverage-governance/todos/documentation-full-coverage-governance-tracking.md b/ai-plan/public/documentation-full-coverage-governance/todos/documentation-full-coverage-governance-tracking.md index 1ff39bb7..28ca5186 100644 --- a/ai-plan/public/documentation-full-coverage-governance/todos/documentation-full-coverage-governance-tracking.md +++ b/ai-plan/public/documentation-full-coverage-governance/todos/documentation-full-coverage-governance-tracking.md @@ -12,11 +12,11 @@ ## 当前恢复点 -- 恢复点编号:`DOCUMENTATION-FULL-COVERAGE-GOV-RP-002` -- 当前阶段:`Phase 2 - Ecs Runtime Docs Refresh` +- 恢复点编号:`DOCUMENTATION-FULL-COVERAGE-GOV-RP-003` +- 当前阶段:`Phase 3 - Cqrs Docs Refresh Preparation` - 当前焦点: - - 重写 `docs/zh-CN/ecs/index.md` 与 `docs/zh-CN/ecs/arch.md` - - 为 `Ecs.Arch` / `Ecs.Arch.Abstractions` 建立 runtime / abstractions / XML 阅读链路 + - 准备进入 `Cqrs` / `Cqrs.Abstractions` / `Cqrs.SourceGenerators` 波次 + - 延续 `README / landing / API reference / XML inventory` 的同一治理模板 - 继续把模块族 inventory 从“入口存在”推进到“可审计的 XML / README / landing 对照表” ## 当前状态摘要 @@ -39,16 +39,20 @@ - 为 `GFramework.Core/README.md`、`GFramework.Core.Abstractions/README.md` 补齐类型族级 XML 覆盖基线入口 - 为 `docs/zh-CN/core/index.md`、`docs/zh-CN/abstractions/core-abstractions.md` 增加“类型族 -> XML 覆盖状态 -> 代表类型”的 inventory - 基于顶层目录轻量盘点确认:`Core` / `Core.Abstractions` 当前公开 / 内部类型声明都已带 XML 注释,成员级审计留待后续波次 + - 重写 `docs/zh-CN/ecs/index.md`,收敛当前 ECS family 的包边界、采用顺序和 XML inventory + - 重写 `docs/zh-CN/ecs/arch.md`,明确 `UseArch(...)` 需早于 `Initialize()` 的真实接入时机 + - 刷新 `GFramework.Ecs.Arch/README.md`,使运行时 README 与源码 / 测试一致 + - 为 `GFramework.Ecs.Arch.Abstractions/README.md` 与 `docs/zh-CN/abstractions/ecs-arch-abstractions.md` 补齐类型族级 XML inventory ## Inventory(第一版) | 模块族 | 当前状态 | 当前证据 | 下一动作 | | --- | --- | --- | --- | | `Core` / `Core.Abstractions` | `README / landing / 类型族级 XML inventory 已收口,成员级审计待补齐` | 根 README、模块 README、`docs/zh-CN/core/**`、`docs/zh-CN/abstractions/core-abstractions.md` 已对齐当前目录与类型族基线 | 进入巡检;如有新 API 变更,再追加成员级 XML 审计 | -| `Cqrs` / `Cqrs.Abstractions` / `Cqrs.SourceGenerators` | `待重写` | README 已存在;站内入口目前分散在 `docs/zh-CN/core/cqrs.md` 与 `docs/zh-CN/source-generators/**` | 在 `Cqrs` 波次里补 dedicated landing / API map 审计 | +| `Cqrs` / `Cqrs.Abstractions` / `Cqrs.SourceGenerators` | `待重写` | README 已存在;站内入口目前分散在 `docs/zh-CN/core/cqrs.md` 与 `docs/zh-CN/source-generators/**` | 进入下一波次,补 dedicated landing / API map 审计 | | `Game` / `Game.Abstractions` / `Game.SourceGenerators` | `已验证` | 根 README、模块 README、`docs/zh-CN/game/**` 和 abstractions 页已存在 | 后续波次补 XML / 教程链路审计 | | `Godot` / `Godot.SourceGenerators` | `已验证` | 上一轮归档 topic 已完成核心 landing / topic / tutorial 校验 | 进入巡检周期,重点看回漂 | -| `Ecs.Arch` / `Ecs.Arch.Abstractions` | `待重写` | runtime README 已存在;`Ecs.Arch.Abstractions` README 与抽象页已在本轮补齐;`docs/zh-CN/ecs/index.md` / `arch.md` 仍偏旧 | 在 `Ecs` 波次重写 runtime docs 并补 XML map | +| `Ecs.Arch` / `Ecs.Arch.Abstractions` | `README / landing / abstractions / 类型族级 XML inventory 已收口,成员级审计待补齐` | `GFramework.Ecs.Arch/README.md`、`GFramework.Ecs.Arch.Abstractions/README.md`、`docs/zh-CN/ecs/**`、`docs/zh-CN/abstractions/ecs-arch-abstractions.md` 已对齐当前源码与测试 | 转入巡检;后续仅在运行时公共 API 变动时补成员级 XML 细审 | | `SourceGenerators.Common` 与 `*.SourceGenerators.Abstractions` | `已判定为内部支撑` | `*.csproj` 明确 `IsPackable=false` | 由所属模块 README 与生成器栏目说明 owner,不建独立采用页 | ## 缺口分级 @@ -66,8 +70,8 @@ ## 当前风险 -- `docs/zh-CN/ecs/index.md` 与 `docs/zh-CN/ecs/arch.md` 仍保留较多早期表述,本轮只先完成 inventory 与入口补齐 - - 缓解措施:把 `Ecs.Arch` 排进前五波次,并把 runtime docs 重写列为该波次的必做项 +- `Cqrs` family 目前仍缺 dedicated landing 与统一 API / XML 阅读链路,站内入口散落在 `core` 与 `source-generators` 栏目 + - 缓解措施:下一恢复点直接进入 `Cqrs` 波次,按 `Core` / `Ecs` 已验证模板重写入口 - 当前 `Core` / `Core.Abstractions` 只完成了类型族级 XML 基线,不等于成员级契约全审计 - 缓解措施:后续只在共享抽象或高风险生命周期接口发生改动时补成员级细审,不在本轮扩张范围 - 其他模块族尚未全部建立同粒度的 XML inventory @@ -100,9 +104,21 @@ - `DOTNET_CLI_HOME=/tmp/dotnet-home dotnet build GFramework.Core.Abstractions/GFramework.Core.Abstractions.csproj -c Release -p:RestoreFallbackFolders=` - 结果:通过 - 备注:`0 Warning(s) / 0 Error(s)` +- `bash .agents/skills/gframework-doc-refresh/scripts/validate-all.sh docs/zh-CN/ecs/index.md` +- 结果:通过 +- 备注:`2026-04-22` 在重写 ECS landing 后重新验证 +- `bash .agents/skills/gframework-doc-refresh/scripts/validate-all.sh docs/zh-CN/ecs/arch.md` +- 结果:通过 +- 备注:`2026-04-22` 在重写 Arch ECS 专题页后重新验证 +- `bash .agents/skills/gframework-doc-refresh/scripts/validate-all.sh docs/zh-CN/abstractions/ecs-arch-abstractions.md` +- 结果:通过 +- 备注:`2026-04-22` 在补充抽象页 XML inventory 后重新验证 +- `cd docs && bun run build` +- 结果:通过 +- 备注:`2026-04-22` 在 Ecs 波次重写后重新构建通过;仅保留 VitePress 大 chunk warning,无构建失败 ## 下一步 -1. 进入 `Ecs` 波次,按源码重写 `docs/zh-CN/ecs/index.md` 与 `docs/zh-CN/ecs/arch.md` -2. 为 `Ecs.Arch` / `Ecs.Arch.Abstractions` 建立与 `Core` 同粒度的 XML / README / landing inventory +1. 进入 `Cqrs` 波次,梳理 `Cqrs` / `Cqrs.Abstractions` / `Cqrs.SourceGenerators` 的模块边界与 docs 入口 +2. 判断是否需要为 `Cqrs` family 新建 dedicated landing,或把现有 `core/cqrs.md` 拆分成模块族入口页 3. 继续为每个模块族补“README / landing / tutorials / API reference / XML”对照表,持续清零 `P0` / `P1` diff --git a/ai-plan/public/documentation-full-coverage-governance/traces/documentation-full-coverage-governance-trace.md b/ai-plan/public/documentation-full-coverage-governance/traces/documentation-full-coverage-governance-trace.md index aefa3a40..bc9aab68 100644 --- a/ai-plan/public/documentation-full-coverage-governance/traces/documentation-full-coverage-governance-trace.md +++ b/ai-plan/public/documentation-full-coverage-governance/traces/documentation-full-coverage-governance-trace.md @@ -62,7 +62,40 @@ - 构建校验: - `cd docs && bun run build`:通过;仅保留 VitePress 大 chunk warning,无构建失败 +### 当前恢复点:RP-003 + +- 完成 `Ecs.Arch` 波次的运行时文档刷新: + - `docs/zh-CN/ecs/index.md` + - `docs/zh-CN/ecs/arch.md` + - `GFramework.Ecs.Arch/README.md` +- 为 `Ecs.Arch.Abstractions` 补齐与运行时页同粒度的 XML inventory: + - `GFramework.Ecs.Arch.Abstractions/README.md` + - `docs/zh-CN/abstractions/ecs-arch-abstractions.md` +- 明确记录一个关键采用事实: + - `UseArch(...)` 必须早于 `Initialize()` 调用 + - 该结论以 `ArchExtensions` 的模块注册方式和 `ExplicitRegistrationTests` 为证据 +- 将 `Ecs.Arch` family 从“入口存在但失真”推进到“README / landing / abstractions / XML inventory 已对齐源码与测试” + +### 当前决策(RP-003) + +- `Ecs` 波次继续采用与 `Core` 相同的治理粒度: + - 模块 README 承担仓库入口 + - `docs/zh-CN/ecs/index.md` 承担模块族 landing + - `docs/zh-CN/ecs/arch.md` 承担运行时默认实现专题页 + - `docs/zh-CN/abstractions/ecs-arch-abstractions.md` 承担契约边界专题页 +- `EnableStatistics` 当前仅保留在公开配置面上;文档不再把它写成已验证的运行时行为 +- 下一恢复点切换到 `Cqrs` 波次,优先解决入口分散和 API / XML 阅读链路不统一的问题 + +### 当前验证(RP-003) + +- 文档校验: + - `validate-all.sh docs/zh-CN/ecs/index.md`:通过 + - `validate-all.sh docs/zh-CN/ecs/arch.md`:通过 + - `validate-all.sh docs/zh-CN/abstractions/ecs-arch-abstractions.md`:通过 +- 构建校验: + - `cd docs && bun run build`:通过;仅保留 VitePress 大 chunk warning,无构建失败 + ### 下一步 -1. 在 `Ecs` 波次重写运行时 docs,并把 `Ecs.Arch.Abstractions` 纳入完整模块闭环 -2. 为 `Ecs.Arch` / `Ecs.Arch.Abstractions` 建立与 `Core` 同粒度的 XML inventory 基线 +1. 在 `Cqrs` 波次核对模块 README、`docs/zh-CN/core/cqrs.md` 与 `docs/zh-CN/source-generators/**` 的真实 owner +2. 决定 `Cqrs` family 是补 dedicated landing 还是拆分现有入口页 diff --git a/docs/zh-CN/abstractions/ecs-arch-abstractions.md b/docs/zh-CN/abstractions/ecs-arch-abstractions.md index 63c04364..bca589c1 100644 --- a/docs/zh-CN/abstractions/ecs-arch-abstractions.md +++ b/docs/zh-CN/abstractions/ecs-arch-abstractions.md @@ -32,6 +32,14 @@ description: GFramework.Ecs.Arch.Abstractions 的契约边界、包关系和最 | `IArchSystemAdapter` | 让 ECS 系统适配到 `ISystem` 生命周期 | | `ArchOptions` | 承载 `WorldCapacity`、`EnableStatistics`、`Priority` 等配置 | +## 类型族级 XML Inventory + +| 类型族 | 代表类型 | XML 状态 | 阅读重点 | +| --- | --- | --- | --- | +| 模块契约 | `IArchEcsModule` | 已覆盖 | 统一更新入口、宿主循环边界 | +| 系统契约 | `IArchSystemAdapter` | 已覆盖 | 只依赖更新接口而不绑定默认 runtime | +| 配置对象 | `ArchOptions` | 已覆盖 | 共享配置字段与跨程序集采用边界 | + ## 最小接入路径 ### 1. 共享模块只依赖更新契约 diff --git a/docs/zh-CN/ecs/arch.md b/docs/zh-CN/ecs/arch.md index e84c8adb..47fd2e95 100644 --- a/docs/zh-CN/ecs/arch.md +++ b/docs/zh-CN/ecs/arch.md @@ -1,46 +1,43 @@ --- title: Arch ECS 集成 -description: GFramework 的 Arch ECS 集成包使用指南,提供高性能的实体组件系统支持。 +description: GFramework.Ecs.Arch 的默认运行时装配路径、系统桥接方式与 XML 阅读入口。 --- # Arch ECS 集成 -## 概述 +`GFramework.Ecs.Arch` 是当前仓库里负责 Arch ECS 默认接入路径的运行时包。它把 Arch `World`、GFramework 的 +`IServiceModule` 生命周期,以及 `AbstractSystem` / `ISystem` 体系桥接到同一条初始化与更新链路中。 -`GFramework.Ecs.Arch` 是 GFramework 的 Arch ECS 集成包,提供开箱即用的 ECS(Entity Component -System)支持。基于 [Arch.Core](https://github.com/genaray/Arch) 实现,具有极致的性能和简洁的 API。 +## 什么时候依赖它 -**主要特性**: +当你需要下面任一能力时,应直接依赖 `GeWuYou.GFramework.Ecs.Arch`: -- 🎯 **显式集成** - 符合 .NET 生态习惯的显式注册方式 -- 🔌 **零依赖** - 不使用时,Core 包无 Arch 依赖 -- 🎯 **类型安全** - 完整的类型系统和编译时检查 -- ⚡ **高性能** - 基于 Arch ECS 的高性能实现 -- 🔧 **易扩展** - 简单的系统适配器模式 -- 📊 **优先级支持** - 系统按优先级顺序执行 +- 在架构实例上调用 `UseArch(...)` +- 让 `World` 在服务模块注册阶段自动创建并注入容器 +- 让 ECS 系统继承 `ArchSystemAdapter` +- 使用仓库自带的 `Position`、`Velocity`、`MovementSystem` 最小示例 -**性能特点**: +如果你只想保留共享边界,而不依赖默认实现,请改看 +[`../abstractions/ecs-arch-abstractions.md`](../abstractions/ecs-arch-abstractions.md)。 -- 10,000 个实体更新 < 100ms -- 1,000 个实体创建 < 50ms -- 基于 Archetype 的高效内存布局 -- 零 GC 分配的组件访问 +## 最小接入路径 -## 安装 +### 1. 安装包 ```bash dotnet add package GeWuYou.GFramework.Ecs.Arch ``` -## 快速开始 +### 2. 在 `Initialize()` 之前调用 `UseArch(...)` -### 1. 注册 ECS 模块 +当前实现通过 `ArchitectureModuleRegistry.Register(...)` 提前登记 `ArchEcsModule`。这意味着调用时机应位于 +`Initialize()` 之前,而不是放进 `OnInitialize()` 里。 ```csharp -using GFramework.Core.Architecture; +using GFramework.Core.Architectures; using GFramework.Ecs.Arch.Extensions; -public class GameArchitecture : Architecture +public sealed class GameArchitecture : Architecture { public GameArchitecture() : base(new ArchitectureConfiguration()) { @@ -48,698 +45,100 @@ public class GameArchitecture : Architecture protected override void OnInitialize() { - // 显式注册 Arch ECS 模块 - this.UseArch(); + RegisterSystem(); } } -// 初始化架构 -var architecture = new GameArchitecture(); +var architecture = new GameArchitecture() + .UseArch(options => + { + options.WorldCapacity = 2048; + options.Priority = 50; + }); + architecture.Initialize(); ``` -### 2. 带配置的注册 +### 3. 用 `ArchSystemAdapter` 编写系统 -```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<T>`: +`ArchSystemAdapter` 在 `OnInit()` 中从当前上下文解析 `World`,再把 Arch 的 `Initialize / BeforeUpdate / +AfterUpdate / Dispose` 钩子桥接到可重写方法。 ```csharp using Arch.Core; using GFramework.Ecs.Arch; -using MyGame.Components; +using GFramework.Ecs.Arch.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) => + var frameDelta = deltaTime; + + World.Query(in _query, (ref Position position, ref Velocity velocity) => { - pos.X += vel.X * deltaTime; - pos.Y += vel.Y * deltaTime; + position.X += velocity.X * frameDelta; + position.Y += velocity.Y * frameDelta; }); } } ``` -### 5. 注册系统 - -```csharp -public class GameArchitecture : Architecture -{ - protected override void OnInitialize() - { - this.UseArch(); - - // 注册 ECS 系统 - RegisterSystem(); - } -} -``` - -### 6. 创建实体 +### 4. 初始化后解析 `World` 与模块服务 ```csharp using Arch.Core; -using GFramework.Core.Abstractions.Rule; -using GFramework.Core.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); - } -} +var world = architecture.Context.GetService(); +var ecsModule = architecture.Context.GetService(); ``` -## 配置选项 - -### ArchOptions +### 5. 由宿主循环显式调用 `Update` ```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; -} +ecsModule.Update(deltaTime); ``` -### 配置示例 +这一步在 `GFramework.Ecs.Arch.Tests/Ecs/*.cs` 中也采用同样的驱动方式。 -```csharp -this.UseArch(options => -{ - // 设置 World 初始容量 - // 根据预期实体数量设置,避免频繁扩容 - options.WorldCapacity = 2000; +## 运行时职责 - // 启用统计信息(开发/调试时使用) - options.EnableStatistics = true; +| 类型 | 责任 | 证据文件 | +| --- | --- | --- | +| `ArchExtensions` | 把 `ArchEcsModule` 注册到 `ArchitectureModuleRegistry` | `GFramework.Ecs.Arch/Extensions/ArchExtensions.cs` | +| `ArchEcsModule` | 创建并注册 `World`,按优先级收集 `ArchSystemAdapter`,负责初始化、销毁和逐帧更新 | `GFramework.Ecs.Arch/ArchEcsModule.cs` | +| `ArchSystemAdapter` | 从 GFramework 系统生命周期桥接到 Arch `ISystem` 生命周期 | `GFramework.Ecs.Arch/ArchSystemAdapter.cs` | +| `ArchOptions` | 暴露 `WorldCapacity`、`EnableStatistics`、`Priority` 这组运行时配置对象 | `GFramework.Ecs.Arch/ArchOptions.cs` | - // 设置模块优先级 - // 数值越小,优先级越高 - options.Priority = 50; -}); -``` +## 配置对象阅读提示 -## 核心概念 +当前公开配置对象是 `GFramework.Ecs.Arch.ArchOptions`。从源码可直接确认: -### Entity(实体) +- `WorldCapacity` 用于 `World.Create(...)` 的容量参数 +- `Priority` 影响 `ArchEcsModule` 作为服务模块的排序 +- `EnableStatistics` 目前保留在公开配置面上;采用时应以源码 XML 注释和实现行为为准,而不是依赖旧文档推断 -实体是游戏世界中的基本对象,本质上是一个唯一标识符: +## 类型族级 XML Inventory -```csharp -// 创建空实体 -var entity = world.Create(); +| 类型族 | 代表类型 | XML 状态 | 阅读重点 | +| --- | --- | --- | --- | +| 装配入口 | `ArchExtensions` | 已覆盖 | `UseArch(...)` 的时机、链式调用返回值 | +| 服务模块 | `ArchEcsModule` | 已覆盖 | `World` 注册、系统收集、模块销毁顺序 | +| 系统桥接层 | `ArchSystemAdapter` | 已覆盖 | `OnArchInitialize` / `OnUpdate` / `OnArchDispose` | +| 示例类型 | `Position`、`Velocity`、`MovementSystem` | 已覆盖 | 组件布局、查询写法、最小集成样例 | -// 创建带组件的实体 -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<T> - -`ArchSystemAdapter<T>` 桥接 Arch.System.ISystem<T> 到 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<T>` 继承自 `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.Core.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) \ No newline at end of file +- ECS 模块总览:[`index.md`](./index.md) +- 抽象契约页:[`../abstractions/ecs-arch-abstractions.md`](../abstractions/ecs-arch-abstractions.md) +- 仓库模块 README:`GFramework.Ecs.Arch/README.md` +- 统一 API / XML 导航:[`../api-reference/index.md`](../api-reference/index.md) diff --git a/docs/zh-CN/ecs/index.md b/docs/zh-CN/ecs/index.md index d0f6602c..2c47e942 100644 --- a/docs/zh-CN/ecs/index.md +++ b/docs/zh-CN/ecs/index.md @@ -1,95 +1,39 @@ --- title: ECS 系统集成 -description: GFramework 的 ECS(Entity Component System)集成方案,支持多种 ECS 框架。 +description: GFramework 当前 ECS 模块族的包边界、采用顺序与 XML 阅读入口。 --- # ECS 系统集成 -## 概述 +GFramework 当前仓库内已经交付并持续维护的 ECS 模块族是 `Ecs.Arch`。它分成运行时实现包 +`GFramework.Ecs.Arch` 和契约包 `GFramework.Ecs.Arch.Abstractions`,分别覆盖默认装配能力与共享边界约定。 -GFramework 提供了灵活的 ECS(Entity Component System)集成方案,允许你根据项目需求选择合适的 ECS 框架。ECS -是一种数据驱动的架构模式,特别适合处理大量相似实体的场景。 +## 当前模块族 -## 什么是 ECS? +| 包 | 适用场景 | 你会得到什么 | 继续阅读 | +| --- | --- | --- | --- | +| `GFramework.Ecs.Arch` | 需要默认运行时、`UseArch(...)` 装配入口、`World` 注册和系统适配基类 | `ArchEcsModule`、`ArchSystemAdapter`、`ArchExtensions.UseArch(...)`、示例组件与系统 | [`arch.md`](./arch.md) | +| `GFramework.Ecs.Arch.Abstractions` | 只想让共享宿主循环、测试替身或扩展模块依赖最小契约,而不引入默认运行时 | `IArchEcsModule`、`IArchSystemAdapter`、`ArchOptions` 契约对象 | [`../abstractions/ecs-arch-abstractions.md`](../abstractions/ecs-arch-abstractions.md) | -ECS(Entity Component System)是一种架构模式,将游戏对象分解为三个核心概念: +## 最小采用路径 -- **Entity(实体)**:游戏世界中的基本对象,本质上是一个唯一标识符 -- **Component(组件)**:纯数据结构,存储实体的状态 -- **System(系统)**:包含游戏逻辑,处理具有特定组件组合的实体 +### 1. 选择包边界 -### ECS 的优势 +- 需要默认实现时安装 `GeWuYou.GFramework.Ecs.Arch` +- 只需要契约时安装 `GeWuYou.GFramework.Ecs.Arch.Abstractions` -- **高性能**:数据局部性好,缓存友好 -- **可扩展**:通过组合组件轻松创建新实体类型 -- **并行处理**:系统之间相互独立,易于并行化 -- **数据驱动**:逻辑与数据分离,便于序列化和网络同步 +### 2. 在 `Initialize()` 前显式接入运行时 -### 何时使用 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 模块 +`UseArch(...)` 通过 `ArchitectureModuleRegistry` 注册服务模块。按当前源码与集成测试,它应在架构实例调用 +`Initialize()` 之前完成。 ```csharp -using GFramework.Core.Architecture; -using GFramework.Ecs.Arc; +using Arch.Core; +using GFramework.Core.Architectures; +using GFramework.Ecs.Arch.Abstractions; +using GFramework.Ecs.Arch.Extensions; -public class GameArchitecture : Architecture +public sealed class GameArchitecture : Architecture { public GameArchitecture() : base(new ArchitectureConfiguration()) { @@ -97,41 +41,29 @@ public class GameArchitecture : Architecture protected override void OnInitialize() { - // 显式注册 Arch ECS 模块 - this.UseArch(options => - { - options.WorldCapacity = 2000; - options.EnableStatistics = true; - }); + RegisterSystem(); } } + +var architecture = new GameArchitecture() + .UseArch(options => + { + options.WorldCapacity = 2048; + options.Priority = 50; + }); + +architecture.Initialize(); + +var world = architecture.Context.GetService(); +var ecsModule = architecture.Context.GetService(); ``` -### 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. 创建系统 +### 3. 让 ECS 系统继承 `ArchSystemAdapter` ```csharp using Arch.Core; using GFramework.Ecs.Arch; +using GFramework.Ecs.Arch.Components; public sealed class MovementSystem : ArchSystemAdapter { @@ -145,147 +77,60 @@ public sealed class MovementSystem : ArchSystemAdapter protected override void OnUpdate(in float deltaTime) { - World.Query(in _query, (ref Position pos, ref Velocity vel) => + var frameDelta = deltaTime; + + World.Query(in _query, (ref Position position, ref Velocity velocity) => { - pos.X += vel.X * deltaTime; - pos.Y += vel.Y * deltaTime; + position.X += velocity.X * frameDelta; + position.Y += velocity.Y * frameDelta; }); } } ``` -### 6. 注册系统 +### 4. 由宿主循环驱动更新 + +`IArchEcsModule` 继承自 `IServiceModule`,负责初始化和销毁;真正的帧更新通过 `Update(float deltaTime)` 显式触发。 ```csharp -public class GameArchitecture : Architecture -{ - protected override void OnInitialize() - { - this.UseArch(); +using GFramework.Ecs.Arch.Abstractions; - // 注册 ECS 系统 - RegisterSystem(); +public sealed class GameLoop +{ + private readonly IArchEcsModule _ecsModule; + + public GameLoop(IArchEcsModule ecsModule) + { + _ecsModule = ecsModule; + } + + public void Tick(float deltaTime) + { + _ecsModule.Update(deltaTime); } } ``` -## 设计理念 +## 阅读顺序 -### 显式集成 +1. 先看本页,确认自己要的是运行时包还是契约包 +2. 需要默认实现时继续读 [`arch.md`](./arch.md) +3. 只想保留共享边界时继续读 [`../abstractions/ecs-arch-abstractions.md`](../abstractions/ecs-arch-abstractions.md) +4. 统一查阅 README / docs / XML 入口时回到 [`../api-reference/index.md`](../api-reference/index.md) -GFramework 采用显式集成的设计,而不是自动注册: +## 类型族级 XML Inventory -```csharp -// ✅ 显式注册 - 清晰、可控 -public class GameArchitecture : Architecture -{ - protected override void OnInitialize() - { - this.UseArch(); // 明确表示使用 Arch ECS - } -} +下表记录当前 `Ecs.Arch` family 的类型声明级 XML 基线,便于从 README、站内 landing 和源码之间建立一致的审计入口。 -// ❌ 自动注册 - 隐式、难以控制 -// 只需引入包,自动注册(不推荐) -``` +| 包 | 类型族 | 代表类型 | XML 状态 | 阅读重点 | +| --- | --- | --- | --- | --- | +| `GFramework.Ecs.Arch` | 运行时装配与模块生命周期 | `ArchExtensions`、`ArchEcsModule` | 已覆盖 | `UseArch(...)` 的接入时机、`World` 注册、模块优先级 | +| `GFramework.Ecs.Arch` | 系统桥接层 | `ArchSystemAdapter` | 已覆盖 | GFramework `ISystem` 生命周期如何桥接到 Arch `ISystem` | +| `GFramework.Ecs.Arch` | 示例组件与系统 | `Position`、`Velocity`、`MovementSystem` | 已覆盖 | 查询写法、组件布局、最小可运行示例 | +| `GFramework.Ecs.Arch.Abstractions` | 契约与配置对象 | `IArchEcsModule`、`IArchSystemAdapter`、`ArchOptions` | 已覆盖 | 共享宿主循环、测试替身、跨程序集配置边界 | -**优势**: +## 边界说明 -- 清晰的依赖关系 -- 更好的 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 使用文档 - -## 相关资源 - -- [Architecture 架构系统](../core/architecture.md) -- [System 系统](../core/system.md) -- [事件系统](../core/events.md) +- 当前仓库没有交付其他可直接消费的 ECS 运行时包;旧文档里把“可能支持的其他 ECS 框架”写成现有能力会误导采用路径。 +- `GFramework.Ecs.Arch.Abstractions` 负责“边界”,`GFramework.Ecs.Arch` 负责“默认实现”。 +- 站内页面只维护可构建的 docs 链路;仓库根 README 和模块 README 继续承担包目录入口职责。