docs(ecs): 重写 Ecs.Arch 文档入口

- 重写 Ecs.Arch README 与 ecs 栏目页面,使采用路径对齐当前源码和集成测试

- 补充 Ecs.Arch.Abstractions 的 XML inventory 与抽象页阅读链路

- 更新 documentation-full-coverage-governance 的恢复点、验证结果和下一波次计划
This commit is contained in:
GeWuYou 2026-04-22 17:19:33 +08:00
parent af21f16c09
commit da0ae700a3
7 changed files with 292 additions and 1035 deletions

View File

@ -33,6 +33,16 @@
| `IArchSystemAdapter.cs` | 让 ECS 系统适配到 GFramework `ISystem` 生命周期的接口 |
| `ArchOptions.cs` | `WorldCapacity``EnableStatistics``Priority` 等配置对象 |
## XML 阅读基线
下表记录当前契约包的类型声明级 XML 基线,方便把 README、站内抽象页与源码阅读顺序对齐。
| 类型族 | 代表类型 | XML 状态 | 阅读重点 |
| --- | --- | --- | --- |
| 模块契约 | `IArchEcsModule` | 已覆盖 | 宿主循环如何统一驱动 ECS 更新 |
| 系统桥接契约 | `IArchSystemAdapter<T>` | 已覆盖 | 外部模块怎样只依赖更新接口而不绑定默认实现 |
| 配置对象 | `ArchOptions` | 已覆盖 | 跨程序集共享 ECS 配置边界 |
## 最小接入路径
### 1. 只想约定宿主循环与 ECS 模块边界

View File

@ -1,16 +1,30 @@
# GFramework.Ecs.Arch
GFramework 的 Arch ECS 集成包,提供开箱即用的 ECSEntity Component System支持
`GFramework.Ecs.Arch``GFramework` 当前 Arch ECS family 的默认运行时实现包
## 特性
它负责把 Arch `World`、GFramework 的服务模块生命周期,以及 `ArchSystemAdapter<T>` 系统桥接到同一条采用路径中。
如果你需要的只是共享契约,请改为依赖 `GFramework.Ecs.Arch.Abstractions`
- 🎯 **显式集成** - 符合 .NET 生态习惯的显式注册方式
- 🔌 **零依赖** - 不使用时Core 包无 Arch 依赖
- 🎯 **类型安全** - 完整的类型系统和编译时检查
- ⚡ **高性能** - 基于 Arch ECS 的高性能实现
- 🔧 **易扩展** - 简单的系统适配器模式
## 包定位
## 快速开始
- 这是运行时实现层,不是纯契约层。
- 适合需要 `UseArch(...)``World` 自动注册、默认模块生命周期和系统桥接基类的项目。
- 常见场景:
- 在架构实例上显式接入 Arch ECS
- 让 `World` 由默认模块创建并放入容器
- 让 ECS 系统复用 `ArchSystemAdapter<float>` 生命周期桥接
- 通过 `IArchEcsModule.Update(deltaTime)` 统一驱动 ECS 帧更新
## 与相邻包的关系
- `GFramework.Core`
- 提供架构、容器、生命周期和系统注册基础设施。
- `GFramework.Ecs.Arch.Abstractions`
- 提供 `IArchEcsModule``IArchSystemAdapter<T>` 和契约层 `ArchOptions`
- `GFramework.Ecs.Arch`
- 提供 `UseArch(...)`、默认 `ArchEcsModule``World` 注册,以及系统适配器基类与示例类型。
## 最小接入路径
### 1. 安装包
@ -18,53 +32,43 @@ GFramework 的 Arch ECS 集成包,提供开箱即用的 ECSEntity 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<MovementSystem>();
}
}
```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<float>
{
@ -78,115 +82,57 @@ public sealed class MovementSystem : ArchSystemAdapter<float>
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<MovementSystem>();
}
}
using Arch.Core;
using GFramework.Ecs.Arch.Abstractions;
var world = architecture.Context.GetService<World>();
var ecsModule = architecture.Context.GetService<IArchEcsModule>();
```
### 7. 创建实体
### 5. 由宿主循环驱动更新
```csharp
var world = this.GetService<World>();
var entity = world.Create(
new Position(0, 0),
new Velocity(1, 1)
);
```
### 8. 更新系统
```csharp
var ecsModule = this.GetService<IArchEcsModule>();
ecsModule.Update(deltaTime);
```
## 配置选项
## 运行时职责地图
### 代码配置
| 文件 | 作用 |
| --- | --- |
| `Extensions/ArchExtensions.cs` | 通过 `UseArch(...)` 把默认模块注册到 `ArchitectureModuleRegistry` |
| `ArchEcsModule.cs` | 创建并注册 `World`,按优先级收集 `ArchSystemAdapter<float>`,负责初始化、销毁和逐帧更新 |
| `ArchSystemAdapter.cs` | 把 GFramework 系统生命周期桥接到 Arch `ISystem<T>` 生命周期 |
| `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<T>` | 已覆盖 | `OnArchInitialize``OnUpdate``OnArchDispose` |
| 示例类型 | `Position``Velocity``MovementSystem` | 已覆盖 | 组件布局、查询写法、最小示例 |
## 架构说明
## 对应文档入口
### 显式注册模式
本包采用 .NET 生态标准的显式注册模式,基于架构实例:
**优点:**
- ✅ 符合 .NET 生态习惯
- ✅ 显式、可控
- ✅ 易于测试和调试
- ✅ 支持配置
- ✅ 支持链式调用
- ✅ 避免"魔法"行为
**使用方式:**
```csharp
// 在架构初始化时添加
var architecture = new GameArchitecture(config)
.UseArch(); // 显式注册
architecture.Initialize();
```
详见:[INTEGRATION_PATTERN.md](INTEGRATION_PATTERN.md)
### 系统适配器
`ArchSystemAdapter<T>` 桥接 Arch.System.ISystem<T> 到 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)

View File

@ -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`

View File

@ -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 还是拆分现有入口页

View File

@ -32,6 +32,14 @@ description: GFramework.Ecs.Arch.Abstractions 的契约边界、包关系和最
| `IArchSystemAdapter<T>` | 让 ECS 系统适配到 `ISystem` 生命周期 |
| `ArchOptions` | 承载 `WorldCapacity``EnableStatistics``Priority` 等配置 |
## 类型族级 XML Inventory
| 类型族 | 代表类型 | XML 状态 | 阅读重点 |
| --- | --- | --- | --- |
| 模块契约 | `IArchEcsModule` | 已覆盖 | 统一更新入口、宿主循环边界 |
| 系统契约 | `IArchSystemAdapter<T>` | 已覆盖 | 只依赖更新接口而不绑定默认 runtime |
| 配置对象 | `ArchOptions` | 已覆盖 | 共享配置字段与跨程序集采用边界 |
## 最小接入路径
### 1. 共享模块只依赖更新契约

View File

@ -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 集成包,提供开箱即用的 ECSEntity Component
System支持。基于 [Arch.Core](https://github.com/genaray/Arch) 实现,具有极致的性能和简洁的 API。
## 什么时候依赖它
**主要特性**
当你需要下面任一能力时,应直接依赖 `GeWuYou.GFramework.Ecs.Arch`
- 🎯 **显式集成** - 符合 .NET 生态习惯的显式注册方式
- 🔌 **零依赖** - 不使用时Core 包无 Arch 依赖
- 🎯 **类型安全** - 完整的类型系统和编译时检查
- ⚡ **高性能** - 基于 Arch ECS 的高性能实现
- 🔧 **易扩展** - 简单的系统适配器模式
- 📊 **优先级支持** - 系统按优先级顺序执行
- 在架构实例上调用 `UseArch(...)`
- 让 `World` 在服务模块注册阶段自动创建并注入容器
- 让 ECS 系统继承 `ArchSystemAdapter<T>`
- 使用仓库自带的 `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<MovementSystem>();
}
}
// 初始化架构
var architecture = new GameArchitecture();
var architecture = new GameArchitecture()
.UseArch(options =>
{
options.WorldCapacity = 2048;
options.Priority = 50;
});
architecture.Initialize();
```
### 2. 带配置的注册
### 3. 用 `ArchSystemAdapter<float>` 编写系统
```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&lt;T&gt;`
`ArchSystemAdapter<T>``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;
/// <summary>
/// 移动系统 - 更新实体位置
/// </summary>
public sealed class MovementSystem : ArchSystemAdapter<float>
{
private QueryDescription _query;
protected override void OnArchInitialize()
{
// 创建查询:查找所有同时拥有 Position 和 Velocity 组件的实体
_query = new QueryDescription()
.WithAll<Position, Velocity>();
}
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<MovementSystem>();
}
}
```
### 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<World>();
// 创建实体
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<IArchEcsModule>();
}
public void Update(float deltaTime)
{
// 更新所有 ECS 系统
_ecsModule.Update(deltaTime);
}
}
var world = architecture.Context.GetService<World>();
var ecsModule = architecture.Context.GetService<IArchEcsModule>();
```
## 配置选项
### ArchOptions
### 5. 由宿主循环显式调用 `Update`
```csharp
public sealed class ArchOptions
{
/// <summary>
/// World 初始容量默认1000
/// </summary>
public int WorldCapacity { get; set; } = 1000;
/// <summary>
/// 是否启用统计信息默认false
/// </summary>
public bool EnableStatistics { get; set; } = false;
/// <summary>
/// 模块优先级默认50
/// </summary>
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<float>`,负责初始化、销毁和逐帧更新 | `GFramework.Ecs.Arch/ArchEcsModule.cs` |
| `ArchSystemAdapter<T>` | 从 GFramework 系统生命周期桥接到 Arch `ISystem<T>` 生命周期 | `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<T>` | 已覆盖 | `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<Position>(entity))
{
// 获取组件引用(零 GC 分配)
ref var pos = ref world.Get<Position>(entity);
pos.X += 10;
}
// 设置组件(替换现有值)
world.Set(entity, new Position(100, 100));
// 移除组件
world.Remove<Velocity>(entity);
```
### System系统
系统包含游戏逻辑,处理具有特定组件组合的实体:
```csharp
public sealed class DamageSystem : ArchSystemAdapter<float>
{
private QueryDescription _query;
protected override void OnArchInitialize()
{
// 初始化查询
_query = new QueryDescription()
.WithAll<Health, Damage>();
}
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<Damage>(entity);
}
});
}
}
```
### World世界
World 是 ECS 的核心容器,管理所有实体和组件:
```csharp
// World 由 ArchEcsModule 自动创建和注册
var world = this.GetService<World>();
// 获取实体数量
var entityCount = world.Size;
// 清空所有实体
world.Clear();
```
## 系统适配器
### ArchSystemAdapter&lt;T&gt;
`ArchSystemAdapter&lt;T&gt;` 桥接 Arch.System.ISystem&lt;T&gt; 到 GFramework 架构:
```csharp
public sealed class MySystem : ArchSystemAdapter<float>
{
// 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<float>
{
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<Position>();
World.Query(in query, (ref Position pos) =>
{
// 处理逻辑
});
}
}
```
### 访问框架服务
`ArchSystemAdapter&lt;T&gt;` 继承自 `AbstractSystem`,可以使用所有 GFramework 的扩展方法:
```csharp
public sealed class ServiceAccessSystem : ArchSystemAdapter<float>
{
protected override void OnUpdate(in float deltaTime)
{
// 获取 Model
var playerModel = this.GetModel<PlayerModel>();
// 获取 Utility
var timeUtility = this.GetUtility<TimeUtility>();
// 发送命令
this.SendCommand(new SaveGameCommand());
// 发送查询
var score = this.SendQuery(new GetScoreQuery());
// 发送事件
this.SendEvent(new GameOverEvent());
}
}
```
## 查询实体
### 基本查询
```csharp
// 查询:必须有 Position 和 Velocity
var query = new QueryDescription()
.WithAll<Position, Velocity>();
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<Health>()
.WithNone<Damage>();
World.Query(in query, (ref Health health) =>
{
// 只处理没有受伤的实体
});
```
### 可选组件查询
```csharp
// 查询:必须有 Position可选 Velocity
var query = new QueryDescription()
.WithAll<Position>()
.WithAny<Velocity>();
World.Query(in query, (Entity entity, ref Position pos) =>
{
// 处理逻辑
});
```
### 访问实体 ID
```csharp
var query = new QueryDescription().WithAll<Position>();
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<float>
{
// ...
}
[Priority(20)] // 中优先级
public sealed class MovementSystem : ArchSystemAdapter<float>
{
// ...
}
[Priority(30)] // 低优先级,后执行
public sealed class RenderSystem : ArchSystemAdapter<float>
{
// ...
}
```
执行顺序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<float>
{
// ✅ 推荐:缓存查询
private QueryDescription _cachedQuery;
protected override void OnArchInitialize()
{
_cachedQuery = new QueryDescription()
.WithAll<Position, Velocity>();
}
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<Position, Velocity, PlayerTag>()
.WithNone<DeadTag>();
```
### 4. 与传统架构结合
```csharp
// ECS 系统可以访问 Model
public class EnemySpawnSystem : ArchSystemAdapter<float>
{
protected override void OnUpdate(in float deltaTime)
{
var gameState = this.GetModel<GameStateModel>();
// 根据关卡生成敌人
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<FastTag>(entity))
{
World.Add(entity, new FastTag());
}
// 动态移除组件
if (pos.X < 0 && World.Has<FastTag>(entity))
{
World.Remove<FastTag>(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<Position>();
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 模块总览:[`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)

View File

@ -1,95 +1,39 @@
---
title: ECS 系统集成
description: GFramework 的 ECSEntity Component System集成方案支持多种 ECS 框架
description: GFramework 当前 ECS 模块族的包边界、采用顺序与 XML 阅读入口
---
# ECS 系统集成
## 概述
GFramework 当前仓库内已经交付并持续维护的 ECS 模块族是 `Ecs.Arch`。它分成运行时实现包
`GFramework.Ecs.Arch` 和契约包 `GFramework.Ecs.Arch.Abstractions`,分别覆盖默认装配能力与共享边界约定。
GFramework 提供了灵活的 ECSEntity Component System集成方案允许你根据项目需求选择合适的 ECS 框架。ECS
是一种数据驱动的架构模式,特别适合处理大量相似实体的场景。
## 当前模块族
## 什么是 ECS
| 包 | 适用场景 | 你会得到什么 | 继续阅读 |
| --- | --- | --- | --- |
| `GFramework.Ecs.Arch` | 需要默认运行时、`UseArch(...)` 装配入口、`World` 注册和系统适配基类 | `ArchEcsModule``ArchSystemAdapter<T>``ArchExtensions.UseArch(...)`、示例组件与系统 | [`arch.md`](./arch.md) |
| `GFramework.Ecs.Arch.Abstractions` | 只想让共享宿主循环、测试替身或扩展模块依赖最小契约,而不引入默认运行时 | `IArchEcsModule``IArchSystemAdapter<T>``ArchOptions` 契约对象 | [`../abstractions/ecs-arch-abstractions.md`](../abstractions/ecs-arch-abstractions.md) |
ECSEntity 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<MovementSystem>();
}
}
var architecture = new GameArchitecture()
.UseArch(options =>
{
options.WorldCapacity = 2048;
options.Priority = 50;
});
architecture.Initialize();
var world = architecture.Context.GetService<World>();
var ecsModule = architecture.Context.GetService<IArchEcsModule>();
```
### 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<float>`
```csharp
using Arch.Core;
using GFramework.Ecs.Arch;
using GFramework.Ecs.Arch.Components;
public sealed class MovementSystem : ArchSystemAdapter<float>
{
@ -145,147 +77,60 @@ public sealed class MovementSystem : ArchSystemAdapter<float>
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<MovementSystem>();
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<T>` | 已覆盖 | GFramework `ISystem` 生命周期如何桥接到 Arch `ISystem<T>` |
| `GFramework.Ecs.Arch` | 示例组件与系统 | `Position``Velocity``MovementSystem` | 已覆盖 | 查询写法、组件布局、最小可运行示例 |
| `GFramework.Ecs.Arch.Abstractions` | 契约与配置对象 | `IArchEcsModule``IArchSystemAdapter<T>``ArchOptions` | 已覆盖 | 共享宿主循环、测试替身、跨程序集配置边界 |
**优势**
## 边界说明
- 清晰的依赖关系
- 更好的 IDE 支持
- 易于测试和调试
- 符合 .NET 生态习惯
### 零依赖原则
如果你不使用 ECSGFramework.Core 包不会引入任何 ECS 相关的依赖:
```xml
<!-- GFramework.Core.csproj -->
<ItemGroup>
<!-- 无 Arch 依赖 -->
</ItemGroup>
<!-- GFramework.Ecs.Arch.csproj -->
<ItemGroup>
<PackageReference Include="Arch" Version="2.1.0" />
<PackageReference Include="Arch.System" Version="1.1.0" />
</ItemGroup>
```
### 模块化设计
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<float>
{
protected override void OnUpdate(in float deltaTime)
{
// 访问 Model
var gameState = this.GetModel<GameStateModel>();
// 根据关卡生成敌人
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<EnemyDestroyedEvent>(OnEnemyDestroyed);
}
private void OnEnemyDestroyed(EnemyDestroyedEvent e)
{
var gameState = this.GetModel<GameStateModel>();
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 继续承担包目录入口职责。