# framework_ecs **Repository Path**: qutin/framework_ecs ## Basic Information - **Project Name**: framework_ecs - **Description**: ARPG — ECS 架构 - **Primary Language**: TypeScript - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-03-19 - **Last Updated**: 2026-03-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # framework_ecs #### 介绍 ARPG — ECS 架构 # 搜打撤 ARPG — ECS 架构说明 > 文档版本: v1.0 > 更新日期: 2026-03-17 > 适用代码路径: `src/` --- ## 一、项目概述 本项目是一款**"搜打撤"ARPG** 游戏的纯逻辑层框架,基于 **ECS(Entity-Component-System)** 架构设计,具备以下核心特性: | 特性 | 说明 | |------|------| | **双世界分离** | LogicWorld(确定性逻辑)与 RenderWorld(可视化渲染)完全解耦 | | **帧同步就绪** | 固定步长逻辑帧 + 定点数运算 + 快照/回滚机制 | | **表驱动配置** | 角色、技能、FSM 转换规则均由配置表驱动 | | **安全防护** | 命令校验 + 关键数值混淆(ObfuscatedInt)+ 完整性 CRC 校验 | | **调试友好** | 可视化 HTML DebugPanel,实时展示双世界状态 | --- ## 二、顶层目录结构 ``` src/ ├── index.ts # 入口文件,创建 GameMain 实例并演示用法 ├── game/ │ └── GameMain.ts # 🎯 游戏主入口,整合所有子系统 ├── ecs/ │ ├── core/ # ECS 核心基础设施 │ │ ├── Entity.ts # 实体定义(仅 ID + 名称) │ │ ├── Component.ts # 组件抽象基类 + 类型 ID 注册 │ │ ├── System.ts # 系统抽象基类(LogicSystem / RenderSystem) │ │ ├── World.ts # 世界基类 —— 管理 E/C/S 的完整生命周期 │ │ ├── Tag.ts # 位运算 Tag/Flag 系统 + 反向索引 │ │ ├── ComponentPool.ts # 组件对象池 │ │ └── index.ts # 导出聚合 │ ├── logic/ # 逻辑层(确定性) │ │ ├── LogicWorld.ts # 逻辑世界(继承 World) │ │ ├── components/ # 逻辑组件 │ │ │ ├── TransformComponent.ts # 位置/旋转(定点数) │ │ │ ├── HealthComponent.ts # 生命值(ObfuscatedInt) │ │ │ ├── CombatComponent.ts # 战斗属性 │ │ │ ├── MoveComponent.ts # 移动数据 │ │ │ └── FSMComponent.ts # 状态机引用 │ │ └── systems/ # 逻辑系统 │ │ ├── FSMSystem.ts # 状态机更新(P50) │ │ ├── MovementSystem.ts # 移动处理(P100) │ │ ├── CombatSystem.ts # 战斗/伤害(P200) │ │ ├── CollisionSystem.ts # 碰撞检测(P300) │ │ └── SpatialHash.ts # 空间哈希加速 │ └── render/ # 渲染层 │ ├── RenderWorld.ts # 渲染世界(继承 World) │ ├── components/ │ │ └── RenderComponents.ts # Sprite / Animator / VFX 组件 │ └── systems/ │ ├── RenderSyncSystem.ts # 逻辑→渲染 数据同步(P0) │ └── AnimationSystem.ts # 动画播放管理(P100) ├── event/ │ ├── EventBus.ts # 事件总线(命令/事件 发布订阅) │ └── EventTypes.ts # 预定义事件和命令类型常量 ├── fsm/ │ └── FSM.ts # 有限状态机(表驱动) ├── sync/ │ ├── FrameSyncManager.ts # 帧同步管理器(命令缓冲/快照/回滚) │ ├── FixedPoint.ts # 定点数运算库(确定性数学) │ └── CommandValidator.ts # 命令合法性校验(防外挂) ├── security/ │ └── IntegrityChecker.ts # 数值完整性 CRC 校验 + ObfuscatedInt ├── table/ │ └── TableManager.ts # 配置表管理器(角色/技能/FSM/AI 表) └── debug/ └── DebugPanel.ts # 可视化调试面板(HTML Overlay) ``` --- ## 三、分层架构总览 ``` ┌───────────────────────────────────────────────────────────────┐ │ index.ts │ │ 应用层 · 创建实例 & Demo │ └─────────────────────┬─────────────────────────────────────────┘ │ ┌─────────────────────▼─────────────────────────────────────────┐ │ GameMain │ │ 游戏主入口 · 整合所有子系统 │ │ ┌──────────┬──────────┬───────────┬──────────┬────────────┐ │ │ │EventBus │TableMgr │FrameSync │Integrity │DebugPanel │ │ │ └────┬─────┴────┬─────┴─────┬─────┴────┬─────┴─────┬──────┘ │ │ │ │ │ │ │ │ │ ┌────▼──────────▼───┐ ┌───▼──────────▼───┐ │ │ │ │ LogicWorld │ │ RenderWorld │ │ │ │ │ (确定性逻辑) │◄─│ (可视化表现) │ │ │ │ │ │ │ │ │ │ │ │ ┌────────────────┐ │ │ ┌──────────────┐ │ │ │ │ │ │ FSMSystem P50│ │ │ │RenderSync P0 │ │ │ │ │ │ │ MoveSys P100 │ │ │ │AnimSys P100 │ │ │ │ │ │ │ CombatSys P200 │ │ │ └──────────────┘ │ │ │ │ │ │ CollSys P300 │ │ │ │ │ │ │ │ └────────────────┘ │ └──────────────────┘ │ │ │ └────────────────────┘ │ │ │ │ │ │ ┌──────────────────────────────────────────────────▼────────┐ │ │ │ 支撑层 │ │ │ │ FixedPoint · CommandValidator · SpatialHash │ │ │ │ ObfuscatedInt · IntegrityChecker · ComponentPool │ │ │ └──────────────────────────────────────────────────────────┘ │ └───────────────────────────────────────────────────────────────┘ ``` --- ## 四、ECS 核心基础设施 (`ecs/core/`) ### 4.1 Entity(实体) | 字段 | 类型 | 说明 | |------|------|------| | `id` | `EntityId (number)` | 全局自增唯一 ID | | `name` | `string` | 可读名称(调试用) | | `alive` | `boolean` | 是否存活 | | `createdAtFrame` | `number` | 创建时的逻辑帧号 | - Entity 本身**只是 ID 载体**,不持有组件引用。 - 提供 `resetIdCounter()` / `getCurrentId()` 静态方法,用于帧同步回滚时恢复 ID 计数器。 ### 4.2 Component(组件) 抽象基类,所有组件必须实现: ```typescript abstract getTypeId(): ComponentTypeId; // 类型 ID(自动注册) abstract getTypeName(): string; // 类型名(调试用) abstract reset(): void; // 重置(对象池复用) abstract clone(): Component; // 深拷贝(快照用) serialize(): any; // 序列化 deserialize(data: any): void; // 反序列化 ``` **类型 ID 注册机制**:使用 `getComponentTypeId(Class)` 函数,通过类名自动分配递增的唯一整数 ID。 ### 4.3 System(系统) ``` System (抽象基) ├── LogicSystem 逻辑系统基类 - 固定步长更新 └── RenderSystem 渲染系统基类 - 可变帧率更新,含插值因子 ``` 核心方法:`init()` / `update(dt)` / `destroy()` 系统按 `priority`(越小越先)排序执行。 ### 4.4 World(世界) 世界基类是 **ECS 的核心容器**,管理: | 功能 | 说明 | |------|------| | **实体管理** | `createEntity` / `createEntityWithId` / `destroyEntity` / `destroyEntityDeferred` | | **组件管理** | `addComponent` / `getComponent` / `removeComponent` / `queryEntities` | | **系统管理** | `addSystem`(自动排序)/ `removeSystem` / 按优先级顺序 `update` | | **查询缓存** | `queryEntities(...)` 结果会缓存,组件增删时自动失效 | | **快照机制** | `createSnapshot()` / `restoreFromSnapshot(snapshot, factory)` | | **延迟操作** | `_deferredActions` 队列,在帧更新完成后批量执行 | ### 4.5 Tag / Flag 系统 - **Tag**:持久标记(如 `TeamA`、`Dead`、`Fighting`),使用 32 位位掩码存储。 - **Flag**:临时帧标记(如 `JustSpawned`、`TookDamage`),每帧开始时自动清除。 - **反向索引**:`TagManager` 内部维护 `Tag → Set` 的反向索引,`getEntitiesByTag()` 时间复杂度为 **O(1)**。 ### 4.6 ComponentPool(组件对象池) - 按 `ComponentTypeId` 管理独立的对象池。 - `acquire()` 获取(优先复用)→ `reset()` 初始化 → 使用 → `release()` 回收。 - 支持 `warmup(count)` 预分配。 --- ## 五、双世界架构 ### 5.1 LogicWorld(逻辑世界) 继承 `World`,额外持有: - `EventBus` — 事件总线引用 - `TableManager` — 配表管理器引用 - 暂停/恢复控制 - `update()` 覆写:先清除临时 Flag → flush 延迟事件 → 执行基类更新 **核心约束**:`measurePerformance = false`,不使用 `performance.now()`,保证确定性。 ### 5.2 RenderWorld(渲染世界) 继承 `World`,额外持有: - `LogicWorld` 引用 — 用于读取逻辑数据 - `interpolation` 插值因子(0~1) — 用于帧间平滑 **核心职责**:将逻辑世界的定点数坐标转换为浮点显示坐标,驱动 LayaAir 节点更新。 ### 5.3 双世界 Entity ID 同步 通过 `createEntityWithId(id)` 保证渲染世界实体 ID 与逻辑世界一致,实现跨世界数据关联。 --- ## 六、组件详解 ### 6.1 逻辑组件 | 组件 | 文件 | 关键字段 | 说明 | |------|------|----------|------| | **TransformComponent** | `TransformComponent.ts` | `position`, `previousPosition`, `rotation`, `scale` | 位置使用 `FixedVec2`(定点数),`previousPosition` 供渲染插值 | | **HealthComponent** | `HealthComponent.ts` | `hp`, `maxHp`, `shield`, `isDead` | 关键数值使用 `ObfuscatedInt` 防篡改;万分比 HP 百分比 | | **CombatComponent** | `CombatComponent.ts` | `attack`, `defense`, `attackSpeed`, `attackRange`, `searchRange`, `targetEntityId` | 攻防使用 `ObfuscatedInt`;范围 ×100 存储;攻速万分比 | | **MoveComponent** | `MoveComponent.ts` | `speed`, `direction`, `targetPosition`, `isMoving`, `speedMultiplier` | 速度/方向均为定点数,支持速度乘数(撤退加速) | | **FSMComponent** | `FSMComponent.ts` | `fsm`, `fsmName` | 持有 FSM 实例引用,名称对应配表 | | **ColliderComponent** | `CollisionSystem.ts` | `radius`, `layer`, `mask`, `isTrigger`, `collidingWith` | 圆形碰撞体 + 层/掩码过滤 | ### 6.2 渲染组件 | 组件 | 说明 | |------|------| | **SpriteComponent** | 精灵显示:资源路径、显示坐标(已插值浮点数)、透明度、颜色叠加、LayaAir 节点引用 | | **AnimatorComponent** | 动画控制:当前/待播动画名、播放速度、循环标记、进度 | | **VFXComponent** | 特效队列管理:请求播放 → 系统消费 → 创建特效节点 | --- ## 七、系统详解 ### 7.1 逻辑系统 按优先级执行顺序: | 优先级 | 系统 | 职责 | |--------|------|------| | **P50** | `FSMSystem` | 遍历所有 FSMComponent,调用 `fsm.update(dt, frame)` 驱动状态机转换 | | **P100** | `MovementSystem` | 处理移动:保存前帧位置 → 计算方向 → 定点数位移 → 到达检测 → 设置 `MovedThisFrame` Flag | | **P200** | `CombatSystem` | 更新攻击冷却 → 目标有效性检查 → 距离检测 → 伤害计算(整数 `攻击力 - 防御力`)→ 发送事件 → 死亡处理 | | **P300** | `CollisionSystem` | 重建 SpatialHash → 宽相位筛选 → 精确圆形碰撞检测 → 碰撞 Enter/Exit 事件 | ### 7.2 渲染系统 | 优先级 | 系统 | 职责 | |--------|------|------| | **P0** | `RenderSyncSystem` | 从 LogicWorld 读取 TransformComponent → 插值计算 → 更新 SpriteComponent 显示坐标 → 驱动 LayaAir 节点 | | **P100** | `AnimationSystem` | 处理 `pendingAnim` → 更新播放进度 → 调用 LayaAir 动画接口 | --- ## 八、事件系统 (`event/`) ### 8.1 EventBus 支持两种通信模式: | 模式 | API | 说明 | |------|-----|------| | **Event(事件)** | `on()` / `emit()` / `post()` | 发布/订阅模式,`post()` 延迟到 `flush()` 时分发 | | **Command(命令)** | `registerCommand()` / `executeCommand()` | 命令处理模式,立即执行 | 特性: - **环形缓冲历史**:事件和命令历史使用 `RingBuffer` 存储,避免 `shift()` 的 O(n) 开销。 - **可信事件标记**:`_trusted` 字段,可配置 `trustedOnly` 模式拒绝外部事件。 - **事件消费**:`consumed` 标记,支持事件拦截。 ### 8.2 预定义类型 **命令类型** (`CommandTypes`):`MOVE`, `STOP`, `ATTACK`, `USE_SKILL`, `SEARCH`, `FIGHT`, `RETREAT`, `INTERACT`, `PICK_ITEM`, `SPAWN_ENTITY`, `DESTROY_ENTITY` **事件类型** (`EventTypes`):`ENTITY_DIED`, `DAMAGE_DEALT`, `FSM_STATE_CHANGED`, `COLLISION_ENTER`, `COLLISION_EXIT`, `FRAME_SYNC_TICK`, `SNAPSHOT_CREATED`, `ROLLBACK_STARTED` 等。 --- ## 九、有限状态机 (`fsm/FSM.ts`) ### 9.1 核心概念 | 概念 | 说明 | |------|------| | **State** | 状态节点,包含 `onEnter` / `onUpdate` / `onExit` 回调 | | **Transition** | 状态转换,包含源/目标状态 + 条件 + 优先级 | | **FSMContext** | 上下文对象:`entityId` + `stateTime` + `blackboard` + `eventBus` | | **Blackboard** | 共享数据黑板,用于状态间通信(如 `nearestEnemy`) | ### 9.2 表驱动 通过 `loadTransitionsFromTable()` 方法,从配表加载转换规则: ``` fromState → toState (conditionType + conditionParams + priority) ``` 条件工厂负责将字符串类型映射为实际判断函数。 ### 9.3 搜打撤 FSM 状态图 ``` ┌──────────┐ phase_start│ │ ┌───────────► search │ │ │ │ │ └────┬─────┘ │ │ enemy_found │ ┌────▼─────┐ │ │ │ hp_below / phase_start │ no_enemy │ fight ├──────────────┐ │◄──────────│ │ │ │ └──────────┘ │ │ │ ┌─┴───────┐ ┌────▼─────┐ │ idle │ reached_safe │ retreat │ │ │◄──────────────────────│ │ └─────────┘ └──────────┘ ▲ ▲ │ ┌──────────┐ │ │ hp_zero│ │ hp_zero │ └─────────┤ dead ├─────────────┘ (ANY *) │ │ (ANY *) └──────────┘ ``` --- ## 十、帧同步系统 (`sync/`) ### 10.1 FrameSyncManager | 功能 | 说明 | |------|------| | **固定步长** | 默认 30fps(33ms/帧)逻辑帧,与渲染帧率解耦 | | **累积器模式** | 使用 `_accumulator` 累积真实时间,逐步消耗逻辑步长 | | **防螺旋死亡** | 单帧最多追赶 5 个逻辑帧,超出则丢弃累积时间 | | **命令缓冲** | `CommandBuffer` 按帧号存储命令,支持未来帧插入 | | **快照管理** | `SnapshotManager` 每 N 帧自动保存世界快照,最多保留 60 个 | | **回滚重放** | `rollback(targetFrame)`: 恢复快照 → 清除后续快照 → 重新模拟到当前帧 | | **命令校验** | 每条命令执行前经过 `CommandValidator` 校验 | ### 10.2 FixedPoint(定点数) - 精度:`1/10000`(4 位小数),内部使用整数存储。 - 提供完整的算术/比较运算:`add` / `sub` / `mul` / `div` / `lerp` / `clamp`。 - **确定性数学**:`isqrt()`(牛顿法整数开方)替代 `Math.sqrt()`。 - `FixedVec2`:二维定点向量,含 `distanceTo` / `normalize` / `scale` 等操作。 ### 10.3 CommandValidator(命令校验) 多层校验流水线: 1. **白名单**:命令类型必须在允许列表中 2. **频率限制**:每秒最多 30 条命令(窗口计数器) 3. **权限校验**:玩家只能操控自己注册的实体 4. **数值范围**:坐标有限性、距离上限、目标 ID 合法性 5. **存活校验**:目标实体必须存在且未死亡 --- ## 十一、安全模块 (`security/`) ### 11.1 ObfuscatedInt(混淆整数) 内存中存储 `value ^ key`(key 每次写入时随机更换),读取时异或还原。防止 Cheat Engine 等工具直接搜索定位数值。 ### 11.2 IntegrityChecker(完整性校验) - 使用 **FNV-1a** 哈希计算校验和。 - `snapshot(entityId, values)` 记录当前校验和。 - `verify(entityId, values, frame)` 比对校验和,不匹配则触发 `onViolation` 回调。 - GameMain 每 30 帧对所有 HealthComponent 执行一次校验。 --- ## 十二、配表系统 (`table/`) ### TableManager 管理所有配置表数据,支持按 ID 查询和条件过滤。 | 配表 | 接口 | 说明 | |------|------|------| | `character` | `CharacterTableRow` | 角色属性:HP、攻防、移速、攻速、搜索/攻击范围、技能列表 | | `skill` | `SkillTableRow` | 技能定义:伤害、冷却、施法时间、类型、动画/特效 | | `fsm` | `FSMTableRow` | FSM 转换规则:源/目标状态、条件类型/参数、优先级 | | `ai` | `AITableRow` | AI 行为参数:搜索/战斗/撤退行为配置 | 支持 `hotReload()` 运行时热更新。 --- ## 十三、调试系统 (`debug/`) ### DebugPanel HTML Overlay 实现的可视化调试面板(仅 `__DEV__` 环境生效): | Tab | 功能 | |-----|------| | **📊 总览** | 性能指标、LogicWorld/RenderWorld 统计、系统列表 | | **👾 实体** | 实体列表(可搜索过滤)、点击展开组件详情 | | **📨 事件** | 事件/命令统计、注册类型、最近历史 | | **🔄 FSM** | 所有状态机状态、转换规则、转换历史、黑板数据 | | **⏱ 帧同步** | 逻辑帧号、FPS、命令缓冲区、快照管理 | | **🌍 双世界** | LogicWorld 与 RenderWorld 并排对比 | 快捷键 `F12` 切换显示/隐藏。 --- ## 十四、技术决策与设计理念 ### 14.1 为何使用定点数? 帧同步要求所有客户端对同一输入产生**完全相同**的输出。JavaScript 的 `number` 是 IEEE 754 双精度浮点数,不同平台可能产生微小差异。定点数 `FixedPoint`(精度 1/10000)使用整数运算,**消除浮点不确定性**。 ### 14.2 为何分离双世界? | 维度 | LogicWorld | RenderWorld | |------|-----------|-------------| | 帧率 | 固定 30fps | 跟随显示器(60/120fps) | | 数值类型 | 定点数 | 浮点数 | | 确定性 | ✅ 必须 | ❌ 不需要 | | 性能计时 | ❌ 禁用 | ✅ 启用 | 两个世界共享 Entity ID,通过 `RenderSyncSystem` 在每个渲染帧从 LogicWorld 读取数据并插值。 ### 14.3 组件数值存储约定 | 约定 | 示例 | |------|------| | 范围类数值 | ×100 存储(`attackRange: 200` = 2.0 格) | | 速度类数值 | 万分比(`attackSpeed: 10000` = 1.0 次/秒) | | HP 百分比 | 万分比(`hpPercent: 5000` = 50%) | | 坐标/距离 | `FixedPoint`(`raw = 值 × 10000`) | --- ## 十五、模块依赖关系 ```mermaid graph TD subgraph 应用层 Index[index.ts] GM[GameMain] end subgraph ECS核心 E[Entity] C[Component] S[System] W[World] T[Tag/Flag] CP[ComponentPool] end subgraph 逻辑层 LW[LogicWorld] TC[TransformComp] HC[HealthComp] CC[CombatComp] MC[MoveComp] FC[FSMComp] COL[ColliderComp] FS[FSMSystem] MS[MovementSystem] CS[CombatSystem] CLS[CollisionSystem] SH[SpatialHash] end subgraph 渲染层 RW[RenderWorld] SC[SpriteComp] AC[AnimatorComp] VC[VFXComp] RSS[RenderSyncSystem] AS[AnimationSystem] end subgraph 支撑层 EB[EventBus] FSM[FSM] FP[FixedPoint] FSY[FrameSyncManager] CV[CommandValidator] IC[IntegrityChecker] TM[TableManager] DP[DebugPanel] end Index --> GM GM --> LW GM --> RW GM --> EB GM --> TM GM --> FSY GM --> IC GM --> DP LW --> W RW --> W W --> E W --> C W --> S W --> T W --> CP CLS --> SH FSY --> CV LW -.-> TC LW -.-> HC LW -.-> CC LW -.-> MC LW -.-> FC LW -.-> COL RW -.-> SC RW -.-> AC RW -.-> VC RSS --> LW ```