新增world概念(多world管理多scene概念)现在支持多个world多个scene同时更新

This commit is contained in:
YHH
2025-08-20 17:48:31 +08:00
parent 69616bbddc
commit a44251cc55
15 changed files with 3539 additions and 783 deletions

171
README.md
View File

@@ -19,16 +19,154 @@ TypeScript ECS (Entity-Component-System) 框架,专为游戏开发设计。
</div>
## ECS 架构原理
## 架构原理
<div align="center">
<img src="assets/svg/ecs-architecture.svg" alt="ECS 架构流程动画" />
</div>
ECS Framework 采用多World + 多Scene的现代化架构设计
ECS 是一种基于组合而非继承的软件架构模式:
- **Entity实体**: 游戏对象的唯一标识
- **Component组件**: 纯数据结构,描述实体属性
- **System系统**: 处理具有特定组件的实体
```mermaid
graph TD
subgraph Main["🎮 ECS Framework - 多World・多Scene架构"]
direction TB
subgraph CoreLayer["⚙️ 核心层 (Core Foundation)"]
direction LR
Core["🔧 <b>Core</b><br/>📋 生命周期管理<br/>⚙️ 配置系统<br/>🔗 平台兼容"]
Registry["📝 <b>ComponentRegistry</b><br/>🏷️ 类型注册<br/>✨ 装饰器支持<br/>🔒 类型安全"]
Pool["🔢 <b>IdentifierPool</b><br/>🆔 实体ID分配<br/>♻️ ID回收<br/>📊 BigInt兼容"]
PoolMgr["♻️ <b>PoolManager</b><br/>🎯 对象池<br/>⚡ 内存优化<br/>📈 性能提升"]
EventBus["📡 <b>EventBus</b><br/>🔄 事件系统<br/>⚡ 异步/同步<br/>🎭 类型安全"]
end
subgraph WorldLayer["🌍 世界管理层 (World Management)"]
direction TB
WorldMgr["🗺️ <b>WorldManager</b><br/>🚀 多World调度<br/>📊 资源管理<br/>🔍 统计监控<br/>🧹 自动清理"]
subgraph WorldsContainer["多World容器"]
direction LR
World1["🌐 <b>GameWorld</b><br/>🎮 游戏逻辑<br/>🌟 全局系统<br/>🔄 跨Scene业务"]
World2["🌐 <b>UIWorld</b><br/>🎨 界面管理<br/>⚡ 独立更新<br/>🔒 资源隔离"]
end
GlobalSys["🎭 <b>Global Systems</b><br/>🌐 NetworkSync<br/>👥 PlayerMgmt<br/>📡 跨Scene通信"]
end
subgraph SceneLayer["🎬 场景层 (Scene Management)"]
direction LR
Scene1["🎯 <b>BattleScene</b><br/>⚔️ 实体管理<br/>🎪 系统调度<br/>⚡ 高性能处理"]
Scene2["🎯 <b>MenuScene</b><br/>🎨 界面逻辑<br/>🔄 生命周期<br/>💾 状态管理"]
Scene3["🎯 <b>UIScene</b><br/>📦 组件存储<br/>🔍 查询引擎<br/>🎭 交互处理"]
end
subgraph ECLayer["🤖 实体组件层 (Entity-Component System)"]
direction TB
subgraph EntityMgmt["📦 实体管理 (Entity Management)"]
direction LR
EntityMgr["👥 <b>EntityManager</b><br/>📋 集合管理<br/>🌳 层次结构<br/>⚡ 高效操作"]
Entities["🎭 <b>Entities</b><br/>👤 Player<br/>👹 Enemy<br/>💥 Bullet<br/>🎯 轻量容器"]
end
subgraph ComponentStore["🧩 组件存储 (Component Storage)"]
direction LR
Storage["💾 <b>ComponentStorage</b><br/>📊 SoA模式<br/>📚 AoS模式<br/>⚡ 内存优化"]
StorageMgr["🗄️ <b>StorageManager</b><br/>🏷️ 类型管理<br/>🔄 脏标记<br/>📈 性能监控"]
Components["🎲 <b>Components</b><br/>📍 Position<br/>🏃 Velocity<br/>❤️ Health<br/>📊 纯数据"]
end
end
subgraph SystemLayer["⚡ 系统层 (System Processing)"]
direction TB
subgraph EntitySys["🔄 实体系统 (Entity Systems)"]
direction LR
EntitySystems["🎪 <b>EntitySystems</b><br/>🏃 MovementSystem<br/>🎨 RenderSystem<br/>🧠 AISystem<br/>⚡ 业务逻辑"]
Processors["📋 <b>EntityProcessors</b><br/>🎯 调度管理<br/>📊 优先级<br/>⚡ 批量处理"]
end
end
subgraph QueryLayer["🔍 查询优化层 (Query & Optimization)"]
direction LR
Matcher["🎯 <b>Matcher</b><br/>✅ withAll<br/>🔄 withAny<br/>❌ withNone<br/>🌊 流式API<br/>💾 智能缓存"]
QuerySys["🔎 <b>QuerySystem</b><br/>⚡ 实时查询<br/>📦 批量优化<br/>🔄 自动更新"]
Archetype["🏗️ <b>ArchetypeSystem</b><br/>📊 组件分组<br/>🎯 原型缓存<br/>💻 BitSet优化"]
end
subgraph DebugLayer["📊 监控调试层 (Debug & Monitoring)"]
direction LR
Debug["🐛 <b>DebugManager</b><br/>🌐 WebSocket调试<br/>🎮 Cocos Creator插件<br/>📸 内存快照"]
Perf["📈 <b>PerformanceMonitor</b><br/>📊 性能统计<br/>⚠️ 阈值告警<br/>📱 实时监控"]
Logger["📋 <b>Logger</b><br/>📊 分级日志<br/>🎨 彩色输出<br/>🔧 自定义处理器"]
end
end
%% 连接关系 - 使用更丰富的箭头样式
Core -.->|初始化| WorldMgr
Core -.->|注册| Registry
Core -.->|分配| Pool
Core -.->|管理| PoolMgr
Core -.->|事件| EventBus
WorldMgr ==>|调度| World1
WorldMgr ==>|调度| World2
World1 -.->|管理| GlobalSys
World1 ==>|包含| Scene1
World1 ==>|包含| Scene2
World2 ==>|包含| Scene3
Scene1 -->|使用| EntityMgr
Scene2 -->|使用| EntityMgr
Scene3 -->|使用| EntityMgr
EntityMgr -->|管理| Entities
Entities -->|附加| Components
Scene1 -->|存储| Storage
Scene2 -->|存储| Storage
Scene3 -->|存储| Storage
Storage -->|管理| StorageMgr
Scene1 -->|调度| EntitySystems
Scene2 -->|调度| EntitySystems
Scene3 -->|调度| EntitySystems
EntitySystems -->|处理| Processors
EntitySystems -->|查询| Matcher
Matcher -->|缓存| QuerySys
QuerySys -->|优化| Archetype
Core -.->|调试| Debug
Core -.->|监控| Perf
Core -.->|日志| Logger
%% 样式定义 - 使用Mermaid支持的语法
classDef coreStyle fill:#E3F2FD,stroke:#1976D2,stroke-width:3px,color:#0D47A1
classDef worldStyle fill:#F3E5F5,stroke:#7B1FA2,stroke-width:3px,color:#4A148C
classDef sceneStyle fill:#FFF3E0,stroke:#F57C00,stroke-width:3px,color:#E65100
classDef entityStyle fill:#E8F5E8,stroke:#388E3C,stroke-width:3px,color:#1B5E20
classDef systemStyle fill:#FCE4EC,stroke:#C2185B,stroke-width:3px,color:#880E4F
classDef queryStyle fill:#E0F2F1,stroke:#00695C,stroke-width:3px,color:#004D40
classDef debugStyle fill:#FFF8E1,stroke:#F9A825,stroke-width:3px,color:#FF8F00
class Core,Registry,Pool,PoolMgr,EventBus coreStyle
class WorldMgr,World1,World2,GlobalSys worldStyle
class Scene1,Scene2,Scene3 sceneStyle
class EntityMgr,Entities,Storage,StorageMgr,Components entityStyle
class EntitySystems,Processors systemStyle
class Matcher,QuerySys,Archetype queryStyle
class Debug,Perf,Logger debugStyle
```
### 核心概念
| 概念 | 职责 | 特点 |
|------|------|------|
| **Entity** | 游戏对象唯一标识 | 轻量级容器,无业务逻辑 |
| **Component** | 纯数据结构 | 描述实体属性支持SoA优化 |
| **System** | 业务逻辑处理 | 操作组件数据,可热插拔 |
| **Scene** | 实体和系统容器 | 独立的游戏场景 |
| **World** | Scene和全局系统容器 | 支持跨Scene的全局逻辑 |
| **WorldManager** | 多World管理 | 统一调度和资源管理 |
## 特性
@@ -201,11 +339,20 @@ class GameSystem {
### SoA 存储优化
<div align="center">
<img src="assets/svg/soa-vs-aos.svg" alt="SoA vs AoS 数据结构对比" />
</div>
针对大规模实体处理的内存布局优化:
用于大规模实体处理:
| 存储方式 | 内存布局 | 适用场景 | 性能特点 |
|----------|----------|----------|----------|
| **AoS** (Array of Structures) | `[{x,y,z}, {x,y,z}, {x,y,z}]` | 通用场景 | 访问灵活,缓存效率一般 |
| **SoA** (Structure of Arrays) | `{x:[1,2,3], y:[4,5,6], z:[7,8,9]}` | 批量处理 | SIMD优化缓存友好 |
**SoA 优势:**
- 🚀 提升 2-4x 批量处理性能
- 💾 更好的CPU缓存利用率
- 🔧 支持SIMD向量化操作
- ⚡ 减少内存访问跳跃
用法示例:
```typescript
import { EnableSoA, Float32, Int32 } from '@esengine/ecs-framework';

View File

@@ -1,382 +0,0 @@
<svg width="1200" height="850" xmlns="http://www.w3.org/2000/svg">
<defs>
<!-- 渐变定义 - 柔和色调 -->
<linearGradient id="coreGradient" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#8892b0"/>
<stop offset="100%" style="stop-color:#a5b4cb"/>
</linearGradient>
<linearGradient id="sceneGradient" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#7c9cbf"/>
<stop offset="100%" style="stop-color:#9bb5d1"/>
</linearGradient>
<linearGradient id="entityGradient" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#81b29a"/>
<stop offset="100%" style="stop-color:#a8caba"/>
</linearGradient>
<linearGradient id="componentGradient" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#d4a574"/>
<stop offset="100%" style="stop-color:#e5c7a0"/>
</linearGradient>
<linearGradient id="systemGradient" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#c49799"/>
<stop offset="100%" style="stop-color:#d9b5b7"/>
</linearGradient>
<linearGradient id="queryGradient" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#b0c4de"/>
<stop offset="100%" style="stop-color:#d0dff0"/>
</linearGradient>
<linearGradient id="eventGradient" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#c5a3c5"/>
<stop offset="100%" style="stop-color:#e0c4e0"/>
</linearGradient>
<!-- 动画定义 -->
<style>
.data-flow-line {
animation: dataFlow 6s linear infinite;
}
@keyframes dataFlow {
0% { stroke-dashoffset: 40; }
100% { stroke-dashoffset: 0; }
}
</style>
</defs>
<!-- 背景 -->
<rect width="1200" height="850" fill="white" rx="15" stroke="#e2e8f0" stroke-width="1"/>
<!-- 标题 -->
<text x="600" y="30" text-anchor="middle" font-family="Arial, sans-serif" font-size="24" font-weight="bold" fill="#2c3e50">
ECS Framework 完整架构
</text>
<!-- Core 核心层 -->
<g id="core-layer">
<!-- 流程步骤标号 -->
<circle cx="480" cy="75" r="15" fill="#8892b0" stroke="white" stroke-width="2"/>
<text x="480" y="81" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" font-weight="bold" fill="white">1</text>
<rect x="400" y="60" width="400" height="60" rx="10" fill="url(#coreGradient)" opacity="0.9"/>
<text x="600" y="85" text-anchor="middle" font-family="Arial, sans-serif" font-size="16" font-weight="bold" fill="white">
Core 框架核心
</text>
<text x="500" y="105" text-anchor="middle" font-family="Arial, sans-serif" font-size="10" fill="white">
ComponentRegistry • IdentifierPool
</text>
<text x="700" y="105" text-anchor="middle" font-family="Arial, sans-serif" font-size="10" fill="white">
EventBus • ConfigManager
</text>
</g>
<!-- Scene 场景管理层 -->
<g id="scene-layer">
<!-- 流程步骤标号 -->
<circle cx="280" cy="175" r="15" fill="#7c9cbf" stroke="white" stroke-width="2"/>
<text x="280" y="181" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" font-weight="bold" fill="white">2</text>
<rect x="300" y="150" width="600" height="80" rx="12" fill="url(#sceneGradient)" opacity="0.9"/>
<text x="600" y="175" text-anchor="middle" font-family="Arial, sans-serif" font-size="18" font-weight="bold" fill="white">
Scene 场景管理器
</text>
<text x="450" y="195" text-anchor="middle" font-family="Arial, sans-serif" font-size="10" fill="white">
EntityList
</text>
<text x="600" y="195" text-anchor="middle" font-family="Arial, sans-serif" font-size="10" fill="white">
ComponentStorageManager
</text>
<text x="750" y="195" text-anchor="middle" font-family="Arial, sans-serif" font-size="10" fill="white">
EntityProcessors
</text>
<text x="600" y="215" text-anchor="middle" font-family="Arial, sans-serif" font-size="10" fill="white">
实体管理 • 组件存储 • 系统调度 • 查询引擎
</text>
</g>
<!-- Entity 实体层 -->
<g id="entity-layer">
<!-- 流程步骤标号 -->
<circle cx="30" cy="320" r="15" fill="#81b29a" stroke="white" stroke-width="2"/>
<text x="30" y="326" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" font-weight="bold" fill="white">3</text>
<rect x="50" y="280" width="280" height="180" rx="10" fill="url(#entityGradient)" opacity="0.9"/>
<text x="190" y="305" text-anchor="middle" font-family="Arial, sans-serif" font-size="16" font-weight="bold" fill="white">
Entity 实体系统
</text>
<!-- Entity Manager -->
<rect x="70" y="320" width="240" height="30" rx="5" fill="rgba(255,255,255,0.3)" stroke="rgba(255,255,255,0.5)" stroke-width="1"/>
<text x="190" y="340" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" fill="white">
EntityList • 高性能实体集合管理
</text>
<!-- Entity instances -->
<rect x="80" y="360" width="60" height="20" rx="3" fill="rgba(255,255,255,0.4)"/>
<text x="110" y="373" text-anchor="middle" font-family="Arial, sans-serif" font-size="9" fill="white">Player</text>
<rect x="150" y="360" width="60" height="20" rx="3" fill="rgba(255,255,255,0.4)"/>
<text x="180" y="373" text-anchor="middle" font-family="Arial, sans-serif" font-size="9" fill="white">Enemy</text>
<rect x="220" y="360" width="60" height="20" rx="3" fill="rgba(255,255,255,0.4)"/>
<text x="250" y="373" text-anchor="middle" font-family="Arial, sans-serif" font-size="9" fill="white">Bullet</text>
<!-- Entity features -->
<text x="80" y="400" font-family="Arial, sans-serif" font-size="9" fill="white">• 组件容器</text>
<text x="80" y="415" font-family="Arial, sans-serif" font-size="9" fill="white">• 层次结构</text>
<text x="190" y="400" font-family="Arial, sans-serif" font-size="9" fill="white">• 生命周期管理</text>
<text x="190" y="415" font-family="Arial, sans-serif" font-size="9" fill="white">• 状态管理</text>
<text x="190" y="440" text-anchor="middle" font-family="Arial, sans-serif" font-size="10" fill="white">
唯一标识 • 无数据逻辑载体
</text>
</g>
<!-- Component 组件层 -->
<g id="component-layer">
<!-- 流程步骤标号 -->
<circle cx="650" cy="320" r="15" fill="#d4a574" stroke="white" stroke-width="2"/>
<text x="650" y="326" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" font-weight="bold" fill="white">4</text>
<rect x="360" y="280" width="280" height="180" rx="10" fill="url(#componentGradient)" opacity="0.9"/>
<text x="500" y="305" text-anchor="middle" font-family="Arial, sans-serif" font-size="16" font-weight="bold" fill="white">
Component 组件系统
</text>
<!-- Component Storage -->
<rect x="380" y="315" width="240" height="40" rx="5" fill="rgba(255,255,255,0.3)" stroke="rgba(255,255,255,0.5)" stroke-width="1"/>
<text x="500" y="330" text-anchor="middle" font-family="Arial, sans-serif" font-size="11" fill="white">
ComponentStorageManager • SoA/AoS 双模式
</text>
<text x="500" y="345" text-anchor="middle" font-family="Arial, sans-serif" font-size="9" fill="white">
ComponentPool • DirtyTrackingSystem
</text>
<!-- Component types -->
<rect x="380" y="360" width="110" height="18" rx="2" fill="rgba(255,255,255,0.4)"/>
<text x="435" y="372" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="white">Position {x,y,z}</text>
<rect x="500" y="360" width="110" height="18" rx="2" fill="rgba(255,255,255,0.4)"/>
<text x="555" y="372" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="white">Velocity {dx,dy,dz}</text>
<rect x="380" y="385" width="110" height="18" rx="2" fill="rgba(255,255,255,0.4)"/>
<text x="435" y="397" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="white">Health {hp,max}</text>
<rect x="500" y="385" width="110" height="18" rx="2" fill="rgba(255,255,255,0.4)"/>
<text x="555" y="397" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="white">Render {sprite}</text>
<!-- Component features -->
<text x="380" y="420" font-family="Arial, sans-serif" font-size="9" fill="white">• @EnableSoA 优化</text>
<text x="520" y="420" font-family="Arial, sans-serif" font-size="9" fill="white">• 对象池管理</text>
<text x="380" y="435" font-family="Arial, sans-serif" font-size="9" fill="white">• 序列化支持</text>
<text x="520" y="435" font-family="Arial, sans-serif" font-size="9" fill="white">• 类型安全</text>
<text x="500" y="450" text-anchor="middle" font-family="Arial, sans-serif" font-size="10" fill="white">
纯数据结构 • 描述实体属性
</text>
</g>
<!-- System 系统层 -->
<g id="system-layer">
<!-- 流程步骤标号 -->
<circle cx="1160" cy="320" r="15" fill="#c49799" stroke="white" stroke-width="2"/>
<text x="1160" y="326" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" font-weight="bold" fill="white">5</text>
<rect x="870" y="280" width="280" height="180" rx="10" fill="url(#systemGradient)" opacity="0.9"/>
<text x="1010" y="305" text-anchor="middle" font-family="Arial, sans-serif" font-size="16" font-weight="bold" fill="white">
System 系统层
</text>
<!-- System Processors -->
<rect x="890" y="320" width="240" height="30" rx="5" fill="rgba(255,255,255,0.3)" stroke="rgba(255,255,255,0.5)" stroke-width="1"/>
<text x="1010" y="340" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" fill="white">
EntityProcessors • 系统调度管理
</text>
<!-- System instances -->
<rect x="890" y="360" width="110" height="18" rx="2" fill="rgba(255,255,255,0.4)"/>
<text x="945" y="372" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="white">MovementSystem</text>
<rect x="1010" y="360" width="110" height="18" rx="2" fill="rgba(255,255,255,0.4)"/>
<text x="1065" y="372" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="white">RenderSystem</text>
<rect x="890" y="385" width="110" height="18" rx="2" fill="rgba(255,255,255,0.4)"/>
<text x="945" y="397" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="white">PhysicsSystem</text>
<rect x="1010" y="385" width="110" height="18" rx="2" fill="rgba(255,255,255,0.4)"/>
<text x="1065" y="397" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="white">AISystem</text>
<!-- System features -->
<text x="890" y="420" font-family="Arial, sans-serif" font-size="9" fill="white">• Matcher 查询</text>
<text x="1020" y="420" font-family="Arial, sans-serif" font-size="9" fill="white">• 性能监控</text>
<text x="890" y="435" font-family="Arial, sans-serif" font-size="9" fill="white">• 优先级调度</text>
<text x="1020" y="435" font-family="Arial, sans-serif" font-size="9" fill="white">• 热插拔</text>
<text x="1010" y="450" text-anchor="middle" font-family="Arial, sans-serif" font-size="10" fill="white">
业务逻辑处理 • 操作组件数据
</text>
</g>
<!-- Query 查询层 -->
<g id="query-layer">
<!-- 流程步骤标号 -->
<circle cx="30" cy="540" r="15" fill="#b0c4de" stroke="white" stroke-width="2"/>
<text x="30" y="546" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" font-weight="bold" fill="white">6</text>
<rect x="50" y="500" width="500" height="120" rx="10" fill="url(#queryGradient)" opacity="0.9"/>
<text x="300" y="525" text-anchor="middle" font-family="Arial, sans-serif" font-size="16" font-weight="bold" fill="#2c3e50">
Query 查询系统
</text>
<!-- Query components -->
<rect x="70" y="540" width="140" height="60" rx="5" fill="rgba(255,255,255,0.6)" stroke="rgba(255,255,255,0.8)" stroke-width="1"/>
<text x="140" y="555" text-anchor="middle" font-family="Arial, sans-serif" font-size="11" font-weight="bold" fill="#4a5568">Matcher</text>
<text x="140" y="570" text-anchor="middle" font-family="Arial, sans-serif" font-size="9" fill="#4a5568">withAll()</text>
<text x="140" y="582" text-anchor="middle" font-family="Arial, sans-serif" font-size="9" fill="#4a5568">withAny()</text>
<text x="140" y="594" text-anchor="middle" font-family="Arial, sans-serif" font-size="9" fill="#4a5568">withNone()</text>
<rect x="230" y="540" width="140" height="60" rx="5" fill="rgba(255,255,255,0.6)" stroke="rgba(255,255,255,0.8)" stroke-width="1"/>
<text x="300" y="555" text-anchor="middle" font-family="Arial, sans-serif" font-size="11" font-weight="bold" fill="#4a5568">QuerySystem</text>
<text x="300" y="570" text-anchor="middle" font-family="Arial, sans-serif" font-size="9" fill="#4a5568">查询缓存</text>
<text x="300" y="582" text-anchor="middle" font-family="Arial, sans-serif" font-size="9" fill="#4a5568">批量优化</text>
<text x="300" y="594" text-anchor="middle" font-family="Arial, sans-serif" font-size="9" fill="#4a5568">实时更新</text>
<rect x="390" y="540" width="140" height="60" rx="5" fill="rgba(255,255,255,0.6)" stroke="rgba(255,255,255,0.8)" stroke-width="1"/>
<text x="460" y="553" text-anchor="middle" font-family="Arial, sans-serif" font-size="11" font-weight="bold" fill="#4a5568">ArchetypeSystem</text>
<text x="460" y="568" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#4a5568">组件组合分组</text>
<text x="460" y="580" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#4a5568">原型级缓存</text>
<text x="460" y="592" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="#4a5568">BitSet优化查询</text>
</g>
<!-- Event 事件系统 -->
<g id="event-layer">
<!-- 流程步骤标号 -->
<circle cx="1160" cy="540" r="15" fill="#c5a3c5" stroke="white" stroke-width="2"/>
<text x="1160" y="546" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" font-weight="bold" fill="white">7</text>
<rect x="580" y="500" width="570" height="120" rx="10" fill="url(#eventGradient)" opacity="0.9"/>
<text x="865" y="525" text-anchor="middle" font-family="Arial, sans-serif" font-size="16" font-weight="bold" fill="#2c3e50">
Event 事件系统
</text>
<!-- Event components -->
<rect x="600" y="540" width="150" height="60" rx="5" fill="rgba(255,255,255,0.6)" stroke="rgba(255,255,255,0.8)" stroke-width="1"/>
<text x="675" y="555" text-anchor="middle" font-family="Arial, sans-serif" font-size="11" font-weight="bold" fill="#4a5568">TypeSafeEventSystem</text>
<text x="675" y="570" text-anchor="middle" font-family="Arial, sans-serif" font-size="9" fill="#4a5568">同步/异步</text>
<text x="675" y="582" text-anchor="middle" font-family="Arial, sans-serif" font-size="9" fill="#4a5568">优先级排序</text>
<text x="675" y="594" text-anchor="middle" font-family="Arial, sans-serif" font-size="9" fill="#4a5568">批处理机制</text>
<rect x="770" y="540" width="150" height="60" rx="5" fill="rgba(255,255,255,0.6)" stroke="rgba(255,255,255,0.8)" stroke-width="1"/>
<text x="845" y="555" text-anchor="middle" font-family="Arial, sans-serif" font-size="11" font-weight="bold" fill="#4a5568">Performance Monitor</text>
<text x="845" y="570" text-anchor="middle" font-family="Arial, sans-serif" font-size="9" fill="#4a5568">性能统计</text>
<text x="845" y="582" text-anchor="middle" font-family="Arial, sans-serif" font-size="9" fill="#4a5568">阈值告警</text>
<text x="845" y="594" text-anchor="middle" font-family="Arial, sans-serif" font-size="9" fill="#4a5568">实时监控</text>
<rect x="940" y="540" width="150" height="60" rx="5" fill="rgba(255,255,255,0.6)" stroke="rgba(255,255,255,0.8)" stroke-width="1"/>
<text x="1015" y="555" text-anchor="middle" font-family="Arial, sans-serif" font-size="11" font-weight="bold" fill="#4a5568">Debug Manager</text>
<text x="1015" y="570" text-anchor="middle" font-family="Arial, sans-serif" font-size="9" fill="#4a5568">WebSocket通信</text>
<text x="1015" y="582" text-anchor="middle" font-family="Arial, sans-serif" font-size="9" fill="#4a5568">实时调试数据</text>
<text x="1015" y="594" text-anchor="middle" font-family="Arial, sans-serif" font-size="9" fill="#4a5568">内存快照</text>
</g>
<!-- 数据流连接线 -->
<!-- 1. Core to Scene - 初始化流程 -->
<path d="M 600 120 Q 600 135 600 150" stroke="#8892b0" stroke-width="3" fill="none" stroke-dasharray="10,5" class="data-flow-line"/>
<polygon points="595,145 600,150 605,145" fill="#8892b0"/>
<text x="620" y="135" font-family="Arial, sans-serif" font-size="10" fill="#8892b0" font-weight="bold">初始化</text>
<!-- 2. Scene to Entity/Component/System - 管理流程 -->
<path d="M 400 230 Q 300 250 190 280" stroke="#7c9cbf" stroke-width="3" fill="none" stroke-dasharray="8,4" class="data-flow-line"/>
<polygon points="195,275 190,280 200,282" fill="#7c9cbf"/>
<text x="295" y="250" font-family="Arial, sans-serif" font-size="9" fill="#7c9cbf">管理实体</text>
<path d="M 600 230 Q 600 250 500 280" stroke="#7c9cbf" stroke-width="3" fill="none" stroke-dasharray="8,4" class="data-flow-line"/>
<polygon points="495,275 500,280 505,275" fill="#7c9cbf"/>
<text x="550" y="250" font-family="Arial, sans-serif" font-size="9" fill="#7c9cbf">存储组件</text>
<path d="M 800 230 Q 900 250 1010 280" stroke="#7c9cbf" stroke-width="3" fill="none" stroke-dasharray="8,4" class="data-flow-line"/>
<polygon points="1005,275 1010,280 1000,282" fill="#7c9cbf"/>
<text x="905" y="250" font-family="Arial, sans-serif" font-size="9" fill="#7c9cbf">调度系统</text>
<!-- 3. Entity to Component - 组件附加 -->
<path d="M 330 370 Q 350 370 360 370" stroke="#81b29a" stroke-width="3" fill="none" stroke-dasharray="6,3" class="data-flow-line"/>
<polygon points="355,365 360,370 355,375" fill="#81b29a"/>
<text x="345" y="360" font-family="Arial, sans-serif" font-size="9" fill="#81b29a" font-weight="bold">附加组件</text>
<!-- 4. Component to System - 数据处理 -->
<path d="M 640 370 Q 750 370 870 370" stroke="#d4a574" stroke-width="3" fill="none" stroke-dasharray="6,3" class="data-flow-line"/>
<polygon points="865,365 870,370 865,375" fill="#d4a574"/>
<text x="755" y="360" font-family="Arial, sans-serif" font-size="9" fill="#d4a574" font-weight="bold">处理数据</text>
<!-- 5. Scene to Query/Event - 查询和事件 -->
<path d="M 450 230 Q 350 350 300 500" stroke="#b0c4de" stroke-width="2" fill="none" stroke-dasharray="5,2" class="data-flow-line"/>
<polygon points="305,495 300,500 295,495" fill="#b0c4de"/>
<text x="375" y="365" font-family="Arial, sans-serif" font-size="8" fill="#b0c4de">查询支持</text>
<path d="M 750 230 Q 850 350 865 500" stroke="#c5a3c5" stroke-width="2" fill="none" stroke-dasharray="5,2" class="data-flow-line"/>
<polygon points="860,495 865,500 870,495" fill="#c5a3c5"/>
<text x="808" y="365" font-family="Arial, sans-serif" font-size="8" fill="#c5a3c5">事件通知</text>
<!-- 6. Query to System - 查询结果 -->
<path d="M 460 540 Q 680 480 900 380" stroke="#b0c4de" stroke-width="3" fill="none" stroke-dasharray="4,2" class="data-flow-line"/>
<polygon points="895,375 900,380 895,385" fill="#b0c4de"/>
<text x="680" y="470" font-family="Arial, sans-serif" font-size="9" fill="#b0c4de" font-weight="bold">匹配结果</text>
<!-- 7. System回流 - 数据修改和事件 -->
<path d="M 900 400 Q 800 420 700 430 Q 600 440 500 430 Q 400 420 350 400" stroke="#c49799" stroke-width="2" fill="none" stroke-dasharray="3,2" class="data-flow-line"/>
<text x="625" y="415" font-family="Arial, sans-serif" font-size="8" fill="#c49799">修改组件数据</text>
<path d="M 1000 460 Q 1050 480 1100 500" stroke="#c5a3c5" stroke-width="2" fill="none" stroke-dasharray="3,2" class="data-flow-line"/>
<text x="1050" y="475" font-family="Arial, sans-serif" font-size="8" fill="#c5a3c5">触发事件</text>
<!-- 工作流程说明 -->
<g id="workflow">
<rect x="50" y="720" width="1100" height="120" rx="8" fill="rgba(108, 117, 125, 0.05)" stroke="#6c757d" stroke-width="1" stroke-dasharray="5,3"/>
<text x="600" y="745" text-anchor="middle" font-family="Arial, sans-serif" font-size="16" font-weight="bold" fill="#495057">
🔄 ECS 框架7步工作流程
</text>
<!-- 流程步骤详解 -->
<g id="step-details">
<text x="70" y="770" font-family="Arial, sans-serif" font-size="11" fill="#8892b0" font-weight="bold">①初始化</text>
<text x="70" y="785" font-family="Arial, sans-serif" font-size="10" fill="#6c757d">Core.create()</text>
<text x="170" y="770" font-family="Arial, sans-serif" font-size="11" fill="#7c9cbf" font-weight="bold">②场景管理</text>
<text x="170" y="785" font-family="Arial, sans-serif" font-size="10" fill="#6c757d">Scene.initialize()</text>
<text x="280" y="770" font-family="Arial, sans-serif" font-size="11" fill="#81b29a" font-weight="bold">③创建实体</text>
<text x="280" y="785" font-family="Arial, sans-serif" font-size="10" fill="#6c757d">Entity.create()</text>
<text x="380" y="770" font-family="Arial, sans-serif" font-size="11" fill="#d4a574" font-weight="bold">④附加组件</text>
<text x="380" y="785" font-family="Arial, sans-serif" font-size="10" fill="#6c757d">addComponent()</text>
<text x="480" y="770" font-family="Arial, sans-serif" font-size="11" fill="#c49799" font-weight="bold">⑤系统处理</text>
<text x="480" y="785" font-family="Arial, sans-serif" font-size="10" fill="#6c757d">System.process()</text>
<text x="580" y="770" font-family="Arial, sans-serif" font-size="11" fill="#b0c4de" font-weight="bold">⑥查询匹配</text>
<text x="580" y="785" font-family="Arial, sans-serif" font-size="10" fill="#6c757d">Matcher.query()</text>
<text x="680" y="770" font-family="Arial, sans-serif" font-size="11" fill="#c5a3c5" font-weight="bold">⑦事件通知</text>
<text x="680" y="785" font-family="Arial, sans-serif" font-size="10" fill="#6c757d">Event.emit()</text>
</g>
<text x="600" y="810" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" fill="#6c757d">
每帧循环:查询实体 → 匹配组件 → 执行系统逻辑 → 修改数据 → 触发事件 → 性能监控
</text>
<text x="600" y="828" text-anchor="middle" font-family="Arial, sans-serif" font-size="11" fill="#6c757d">
💡 圆形数字显示执行顺序 • 不同颜色连线代表不同数据流
</text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 23 KiB

View File

@@ -1,273 +0,0 @@
<svg width="800" height="500" xmlns="http://www.w3.org/2000/svg">
<defs>
<!-- 渐变定义 -->
<linearGradient id="soaGradient" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#667eea"/>
<stop offset="100%" style="stop-color:#764ba2"/>
</linearGradient>
<linearGradient id="aosGradient" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#f093fb"/>
<stop offset="100%" style="stop-color:#f5576c"/>
</linearGradient>
<linearGradient id="performanceGradient" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#4facfe"/>
<stop offset="100%" style="stop-color:#00f2fe"/>
</linearGradient>
<!-- 动画定义 -->
<style>
.data-flow {
animation: dataMove 3s ease-in-out infinite;
}
.memory-access {
animation: memoryAccess 2s ease-in-out infinite;
}
.performance-bar {
animation: performanceGrow 2.5s ease-out forwards;
}
.text-reveal {
animation: textReveal 1s ease-in forwards;
opacity: 0;
}
.structure-highlight {
animation: structureHighlight 4s ease-in-out infinite;
}
@keyframes dataMove {
0%, 100% { opacity: 0.6; filter: brightness(1); }
50% { opacity: 1; filter: brightness(1.2); }
}
@keyframes memoryAccess {
0%, 100% { fill: #e2e8f0; }
50% { fill: #3182ce; }
}
@keyframes performanceGrow {
0% { width: 0; opacity: 0.5; }
100% { opacity: 1; }
}
@keyframes textReveal {
0% { opacity: 0; }
100% { opacity: 1; }
}
@keyframes structureHighlight {
0%, 100% { stroke: #cbd5e0; stroke-width: 1; opacity: 0.8; }
50% { stroke: #3182ce; stroke-width: 2; opacity: 1; }
}
</style>
</defs>
<!-- 背景 -->
<rect width="800" height="500" fill="white" rx="15" stroke="#e2e8f0" stroke-width="1"/>
<!-- 标题 -->
<text x="400" y="30" text-anchor="middle" font-family="Arial, sans-serif" font-size="22" font-weight="bold" fill="#2c3e50">
SoA vs AoS 数据结构对比
</text>
<text x="400" y="50" text-anchor="middle" font-family="Arial, sans-serif" font-size="14" fill="#666">
Structure of Arrays vs Array of Structures
</text>
<!-- AoS 部分 (左侧) -->
<g id="aos-section">
<rect x="50" y="80" width="320" height="180" rx="10" fill="url(#aosGradient)" opacity="0.9"/>
<!-- AoS 标题 -->
<text x="210" y="105" text-anchor="middle" font-family="Arial, sans-serif" font-size="18" font-weight="bold" fill="white">
AoS - Array of Structures
</text>
<text x="210" y="125" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" fill="white">
结构体数组(传统方式)
</text>
<!-- AoS 数据结构示例 -->
<rect x="70" y="140" width="280" height="100" rx="5" fill="rgba(255,255,255,0.2)" stroke="rgba(255,255,255,0.4)" stroke-width="1"/>
<!-- Entity 0 -->
<rect x="85" y="155" width="70" height="15" rx="2" fill="rgba(255,255,255,0.3)" class="structure-highlight"/>
<text x="120" y="166" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="white">Entity[0]</text>
<rect x="85" y="175" width="15" height="8" rx="1" fill="#ff6b6b" class="data-flow"/>
<text x="92" y="181" text-anchor="middle" font-family="Arial, sans-serif" font-size="6" fill="white">x</text>
<rect x="105" y="175" width="15" height="8" rx="1" fill="#4ecdc4" class="data-flow" style="animation-delay: 0.5s"/>
<text x="112" y="181" text-anchor="middle" font-family="Arial, sans-serif" font-size="6" fill="white">y</text>
<rect x="125" y="175" width="15" height="8" rx="1" fill="#45b7d1" class="data-flow" style="animation-delay: 1s"/>
<text x="132" y="181" text-anchor="middle" font-family="Arial, sans-serif" font-size="6" fill="white">hp</text>
<rect x="145" y="175" width="10" height="8" rx="1" fill="#96ceb4" class="data-flow" style="animation-delay: 1.5s"/>
<text x="150" y="181" text-anchor="middle" font-family="Arial, sans-serif" font-size="6" fill="white">id</text>
<!-- Entity 1 -->
<rect x="170" y="155" width="70" height="15" rx="2" fill="rgba(255,255,255,0.3)" class="structure-highlight" style="animation-delay: 1s"/>
<text x="205" y="166" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="white">Entity[1]</text>
<rect x="170" y="175" width="15" height="8" rx="1" fill="#ff6b6b" class="data-flow" style="animation-delay: 2s"/>
<rect x="190" y="175" width="15" height="8" rx="1" fill="#4ecdc4" class="data-flow" style="animation-delay: 2.5s"/>
<rect x="210" y="175" width="15" height="8" rx="1" fill="#45b7d1" class="data-flow" style="animation-delay: 3s"/>
<rect x="230" y="175" width="10" height="8" rx="1" fill="#96ceb4" class="data-flow" style="animation-delay: 3.5s"/>
<!-- Entity 2 -->
<rect x="255" y="155" width="70" height="15" rx="2" fill="rgba(255,255,255,0.3)" class="structure-highlight" style="animation-delay: 2s"/>
<text x="290" y="166" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="white">Entity[2]</text>
<rect x="255" y="175" width="15" height="8" rx="1" fill="#ff6b6b" class="data-flow" style="animation-delay: 4s"/>
<rect x="275" y="175" width="15" height="8" rx="1" fill="#4ecdc4" class="data-flow" style="animation-delay: 4.5s"/>
<rect x="295" y="175" width="15" height="8" rx="1" fill="#45b7d1" class="data-flow" style="animation-delay: 5s"/>
<rect x="315" y="175" width="10" height="8" rx="1" fill="#96ceb4" class="data-flow" style="animation-delay: 5.5s"/>
<!-- 内存访问模式 -->
<text x="210" y="205" text-anchor="middle" font-family="Arial, sans-serif" font-size="10" fill="white">
内存访问:跳跃式访问,缓存不友好
</text>
<path d="M 92 195 Q 112 210 132 195 Q 152 210 177 195" stroke="white" stroke-width="1" fill="none" stroke-dasharray="3,2"/>
<text x="135" y="225" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="white">
处理位置时需跳过其他数据
</text>
</g>
<!-- SoA 部分 (右侧) -->
<g id="soa-section">
<rect x="430" y="80" width="320" height="180" rx="10" fill="url(#soaGradient)" opacity="0.9"/>
<!-- SoA 标题 -->
<text x="590" y="105" text-anchor="middle" font-family="Arial, sans-serif" font-size="18" font-weight="bold" fill="white">
SoA - Structure of Arrays
</text>
<text x="590" y="125" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" fill="white">
数组结构ECS优化方式
</text>
<!-- SoA 数据结构示例 -->
<rect x="450" y="140" width="280" height="100" rx="5" fill="rgba(255,255,255,0.2)" stroke="rgba(255,255,255,0.4)" stroke-width="1"/>
<!-- Position Array -->
<text x="460" y="155" font-family="Arial, sans-serif" font-size="8" fill="white">Position[]:</text>
<rect x="515" y="145" width="20" height="10" rx="1" fill="#ff6b6b" class="data-flow"/>
<rect x="540" y="145" width="20" height="10" rx="1" fill="#ff6b6b" class="data-flow" style="animation-delay: 0.3s"/>
<rect x="565" y="145" width="20" height="10" rx="1" fill="#ff6b6b" class="data-flow" style="animation-delay: 0.6s"/>
<rect x="590" y="145" width="20" height="10" rx="1" fill="#ff6b6b" class="data-flow" style="animation-delay: 0.9s"/>
<text x="625" y="153" font-family="Arial, sans-serif" font-size="8" fill="white">连续存储</text>
<!-- Velocity Array -->
<text x="460" y="170" font-family="Arial, sans-serif" font-size="8" fill="white">Velocity[]:</text>
<rect x="515" y="160" width="20" height="10" rx="1" fill="#4ecdc4" class="data-flow" style="animation-delay: 1s"/>
<rect x="540" y="160" width="20" height="10" rx="1" fill="#4ecdc4" class="data-flow" style="animation-delay: 1.3s"/>
<rect x="565" y="160" width="20" height="10" rx="1" fill="#4ecdc4" class="data-flow" style="animation-delay: 1.6s"/>
<rect x="590" y="160" width="20" height="10" rx="1" fill="#4ecdc4" class="data-flow" style="animation-delay: 1.9s"/>
<!-- Health Array -->
<text x="460" y="185" font-family="Arial, sans-serif" font-size="8" fill="white">Health[]:</text>
<rect x="515" y="175" width="20" height="10" rx="1" fill="#45b7d1" class="data-flow" style="animation-delay: 2s"/>
<rect x="540" y="175" width="20" height="10" rx="1" fill="#45b7d1" class="data-flow" style="animation-delay: 2.3s"/>
<rect x="565" y="175" width="20" height="10" rx="1" fill="#45b7d1" class="data-flow" style="animation-delay: 2.6s"/>
<rect x="590" y="175" width="20" height="10" rx="1" fill="#45b7d1" class="data-flow" style="animation-delay: 2.9s"/>
<!-- ID Array -->
<text x="460" y="200" font-family="Arial, sans-serif" font-size="8" fill="white">EntityID[]:</text>
<rect x="515" y="190" width="15" height="10" rx="1" fill="#96ceb4" class="data-flow" style="animation-delay: 3s"/>
<rect x="535" y="190" width="15" height="10" rx="1" fill="#96ceb4" class="data-flow" style="animation-delay: 3.3s"/>
<rect x="555" y="190" width="15" height="10" rx="1" fill="#96ceb4" class="data-flow" style="animation-delay: 3.6s"/>
<rect x="575" y="190" width="15" height="10" rx="1" fill="#96ceb4" class="data-flow" style="animation-delay: 3.9s"/>
<!-- 内存访问模式 -->
<text x="590" y="220" text-anchor="middle" font-family="Arial, sans-serif" font-size="10" fill="white">
内存访问:连续访问,缓存友好
</text>
<path d="M 525 205 L 570 205" stroke="white" stroke-width="2" fill="none" class="data-flow"/>
<text x="590" y="235" text-anchor="middle" font-family="Arial, sans-serif" font-size="8" fill="white">
处理位置时连续访问相同类型数据
</text>
</g>
<!-- 性能对比区域 -->
<g id="performance-comparison">
<rect x="50" y="280" width="700" height="150" rx="10" fill="rgba(248, 249, 250, 0.9)" stroke="#e2e8f0" stroke-width="1"/>
<text x="400" y="305" text-anchor="middle" font-family="Arial, sans-serif" font-size="16" font-weight="bold" fill="#2c3e50">
性能对比分析
</text>
<!-- 缓存性能对比 -->
<g id="cache-performance">
<text x="80" y="330" font-family="Arial, sans-serif" font-size="12" font-weight="bold" fill="#4a5568">
缓存命中率:
</text>
<!-- AoS 缓存性能 -->
<text x="80" y="350" font-family="Arial, sans-serif" font-size="11" fill="#666">AoS:</text>
<rect x="120" y="342" width="100" height="12" rx="6" fill="#f7fafc" stroke="#e2e8f0" stroke-width="1"/>
<rect x="120" y="342" width="35" height="12" rx="6" fill="url(#aosGradient)" class="performance-bar"/>
<text x="230" y="351" font-family="Arial, sans-serif" font-size="10" fill="#666">35%</text>
<!-- SoA 缓存性能 -->
<text x="80" y="370" font-family="Arial, sans-serif" font-size="11" fill="#666">SoA:</text>
<rect x="120" y="362" width="100" height="12" rx="6" fill="#f7fafc" stroke="#e2e8f0" stroke-width="1"/>
<rect x="120" y="362" width="85" height="12" rx="6" fill="url(#soaGradient)" class="performance-bar" style="animation-delay: 0.5s"/>
<text x="230" y="371" font-family="Arial, sans-serif" font-size="10" fill="#666">85%</text>
</g>
<!-- 处理速度对比 -->
<g id="processing-speed">
<text x="320" y="330" font-family="Arial, sans-serif" font-size="12" font-weight="bold" fill="#4a5568">
批量处理速度:
</text>
<!-- AoS 处理速度 -->
<text x="320" y="350" font-family="Arial, sans-serif" font-size="11" fill="#666">AoS:</text>
<rect x="360" y="342" width="120" height="12" rx="6" fill="#f7fafc" stroke="#e2e8f0" stroke-width="1"/>
<rect x="360" y="342" width="48" height="12" rx="6" fill="url(#aosGradient)" class="performance-bar" style="animation-delay: 1s"/>
<text x="490" y="351" font-family="Arial, sans-serif" font-size="10" fill="#666">2.3x slower</text>
<!-- SoA 处理速度 -->
<text x="320" y="370" font-family="Arial, sans-serif" font-size="11" fill="#666">SoA:</text>
<rect x="360" y="362" width="120" height="12" rx="6" fill="#f7fafc" stroke="#e2e8f0" stroke-width="1"/>
<rect x="360" y="362" width="120" height="12" rx="6" fill="url(#soaGradient)" class="performance-bar" style="animation-delay: 1.5s"/>
<text x="490" y="371" font-family="Arial, sans-serif" font-size="10" fill="#666">baseline</text>
</g>
<!-- 使用场景 -->
<g id="use-cases">
<text x="560" y="330" font-family="Arial, sans-serif" font-size="12" font-weight="bold" fill="#4a5568">
适用场景:
</text>
<text x="560" y="350" font-family="Arial, sans-serif" font-size="10" fill="#666">
✅ SoA: 大量实体的同类型操作
</text>
<text x="560" y="365" font-family="Arial, sans-serif" font-size="10" fill="#666">
✅ SoA: 游戏循环中的系统处理
</text>
<text x="560" y="380" font-family="Arial, sans-serif" font-size="10" fill="#666">
❌ AoS: 混合操作、少量实体
</text>
<text x="560" y="395" font-family="Arial, sans-serif" font-size="10" fill="#666">
❌ AoS: 随机访问模式
</text>
</g>
</g>
<!-- ECS 框架优势说明 -->
<g id="ecs-advantage">
<rect x="50" y="450" width="700" height="40" rx="8" fill="rgba(67, 233, 123, 0.1)" stroke="#43e97b" stroke-width="1"/>
<text x="400" y="468" text-anchor="middle" font-family="Arial, sans-serif" font-size="14" font-weight="bold" fill="#2d3748">
🚀 本框架采用 SoA 优化存储,@EnableSoA 装饰器自动转换,性能提升 2-3 倍
</text>
<text x="400" y="485" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" fill="#4a5568">
支持热切换存储方式,开发时使用 AoS 调试,生产环境自动启用 SoA 优化
</text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -14,7 +14,7 @@ ECS 架构将传统的面向对象设计分解为三个核心部分:
## Core核心
Core 是框架的核心管理类,负责游戏的生命周期管理。
Core 是框架的核心管理类,负责游戏的生命周期管理。框架采用融合设计既支持传统的单Scene模式向后兼容也支持高级的多World/多Scene架构。
### 创建和配置
@@ -47,6 +47,40 @@ const core2 = Core.create(false); // 发布模式
const core3 = Core.create(); // 默认调试模式
```
### 场景管理API
```typescript
// 单Scene模式默认向后兼容
const scene = new Scene();
Core.setScene(scene); // 设置场景
const currentScene = Core.getScene(); // 获取当前场景
// 多World模式高级功能
Core.enableWorldManager(); // 启用World管理器
const worldManager = Core.getWorldManager();
// 创建World
const gameWorld = worldManager.createWorld('GameWorld', {
name: 'GameWorld',
maxScenes: 10,
autoCleanup: true
});
// 在World中管理Scene
const battleScene = gameWorld.createScene('battle', new Scene());
const uiScene = gameWorld.createScene('ui', new Scene());
gameWorld.setSceneActive('battle', true);
gameWorld.setSceneActive('ui', true);
// 启动World
gameWorld.start();
// 获取World统计
const worldStats = gameWorld.getStats();
console.log('World状态:', worldStats);
```
### 事件系统
```typescript
@@ -404,6 +438,235 @@ console.log("实体数量:", stats.entityCount);
console.log("系统数量:", stats.processorCount);
```
## World世界
World是Scene的容器提供了更高级的场景管理功能。每个World可以包含多个Scene适用于复杂的游戏架构。
### World基本使用
```typescript
import { World, Scene, IWorldConfig } from '@esengine/ecs-framework';
// 创建World配置
const worldConfig: IWorldConfig = {
name: 'GameWorld',
debug: true,
maxScenes: 10,
autoCleanup: true
};
// 创建World
const gameWorld = new World(worldConfig);
// 在World中创建Scene
const battleScene = gameWorld.createScene('battle', new Scene());
const uiScene = gameWorld.createScene('ui', new Scene());
const menuScene = gameWorld.createScene('menu');
// 激活Scene
gameWorld.setSceneActive('battle', true);
gameWorld.setSceneActive('ui', true);
// 启动World
gameWorld.start();
```
### World生命周期管理
```typescript
// 启动World启动所有全局System
gameWorld.start();
// 检查World状态
if (gameWorld.isActive) {
console.log('World正在运行');
}
// 停止World停止所有Scene和全局System
gameWorld.stop();
// 销毁World清理所有资源
gameWorld.destroy();
```
### Scene管理
```typescript
// 获取Scene
const battleScene = gameWorld.getScene<Scene>('battle');
// 检查Scene是否激活
if (gameWorld.isSceneActive('battle')) {
console.log('战斗场景正在运行');
}
// 移除Scene
gameWorld.removeScene('menu');
// 获取所有Scene ID
const sceneIds = gameWorld.getSceneIds();
console.log('所有Scene:', sceneIds);
// 获取活跃Scene数量
const activeCount = gameWorld.getActiveSceneCount();
console.log('活跃Scene数量:', activeCount);
```
### 全局System管理
World支持全局System这些System会在所有Scene之前执行适用于跨Scene的业务逻辑
```typescript
import { IGlobalSystem } from '@esengine/ecs-framework';
// 全局网络同步系统
class GlobalNetworkSystem implements IGlobalSystem {
public readonly name = 'GlobalNetworkSystem';
public initialize(): void {
// 初始化网络连接
console.log('网络系统初始化');
}
public update(): void {
// 处理全局网络同步逻辑
// 注意全局系统处理的是World级别的逻辑不直接处理实体
// 如需处理特定实体请在Scene中使用EntitySystem
this.syncGlobalNetworkState();
}
public reset(): void {
// 重置系统状态
}
public destroy(): void {
// 清理网络连接
console.log('网络系统销毁');
}
private syncGlobalNetworkState(): void {
// 全局网络状态同步
}
}
// 添加全局System
const networkSystem = gameWorld.addGlobalSystem(new GlobalNetworkSystem());
// 获取全局System
const existingSystem = gameWorld.getGlobalSystem(GlobalNetworkSystem);
// 移除全局System
gameWorld.removeGlobalSystem(networkSystem);
```
> **注意**全局System适用于World级别的业务逻辑如网络管理、资源管理、全局状态管理等。如果需要处理具体的实体和组件请在Scene中使用EntitySystem。
### World状态监控
```typescript
// 获取World状态
const status = gameWorld.getStatus();
console.log('World状态:', {
name: status.name,
isActive: status.isActive,
sceneCount: status.sceneCount,
activeSceneCount: status.activeSceneCount,
globalSystemCount: status.globalSystemCount,
scenes: status.scenes
});
// 获取World统计信息
const stats = gameWorld.getStats();
console.log('World统计:', {
totalEntities: stats.totalEntities,
totalSystems: stats.totalSystems,
memoryUsage: stats.memoryUsage
});
```
## WorldManager世界管理器
WorldManager是单例模式的World管理器负责管理多个World实例。
### WorldManager基本使用
```typescript
import { WorldManager, IWorldManagerConfig } from '@esengine/ecs-framework';
// 获取WorldManager实例
const worldManager = WorldManager.getInstance({
maxWorlds: 50,
autoCleanup: true,
debug: true
});
// 或者通过Core获取
Core.enableWorldManager();
const worldManager2 = Core.getWorldManager();
```
### World管理
```typescript
// 创建World
const gameWorld = worldManager.createWorld('GameRoom_001', {
name: 'GameRoom_001',
maxScenes: 5,
autoCleanup: true
});
// 获取World
const existingWorld = worldManager.getWorld('GameRoom_001');
// 检查World是否存在
if (worldManager.getWorld('GameRoom_001')) {
console.log('World存在');
}
// 销毁World
worldManager.removeWorld('GameRoom_001');
// 获取所有World ID
const worldIds = worldManager.getWorldIds();
console.log('所有World ID:', worldIds);
// 获取活跃World
const activeWorlds = worldManager.getActiveWorlds();
console.log('活跃World数量:', activeWorlds.length);
```
### WorldManager统计和监控
```typescript
// 获取WorldManager状态
const managerStatus = worldManager.getStatus();
console.log('WorldManager状态:', {
totalWorlds: managerStatus.totalWorlds,
activeWorlds: managerStatus.activeWorlds,
maxWorlds: managerStatus.maxWorlds,
memoryUsage: managerStatus.memoryUsage
});
// 获取所有World的统计
const allStats = worldManager.getAllWorldStats();
allStats.forEach(stat => {
console.log(`World ${stat.worldName}:`, stat);
});
// 清理空闲World
const cleanedCount = worldManager.cleanup();
console.log(`清理了 ${cleanedCount} 个空闲World`);
```
### 使用场景
World和WorldManager适用于
- **游戏服务器**每个房间一个独立World
- **复杂客户端**按功能分层管理Scene游戏层、UI层、特效层
- **并发世界**:需要同时运行多个独立游戏世界的场景
> **完整示例和最佳实践**:查看 [场景管理完整指南](scene-management-guide.md#world多场景管理) 了解详细的实现方案和架构设计
## System系统
系统处理实体集合,实现游戏的核心逻辑。
@@ -646,11 +909,18 @@ const movingEntities = scene.querySystem.queryAll(PositionComponent, VelocityCom
ECS Framework 提供了完整的实体组件系统架构:
- **Core** 管理游戏生命周期和全局功能
- **Core** 管理游戏生命周期和全局功能支持单Scene和多World模式
- **Entity** 作为游戏对象的基础容器
- **Component** 实现具体的功能模块,支持对象池优化
- **System** 处理游戏逻辑
- **Scene** 管理游戏世界状态,支持批量操作
- **World** 高级场景容器支持多Scene管理和全局System
- **WorldManager** 管理多个World实例适用于复杂架构
- **高级优化** 位掩码优化器、组件对象池、批量操作等
通过合理使用这些核心概念和优化功能,可以构建出高性能、结构清晰、易于维护的游戏代码。
### 架构选择指南
- **单Scene模式**:适合简单游戏、单机游戏、原型开发
- **多World模式**:适合多人游戏服务器、复杂应用、需要场景隔离的项目
框架采用融合设计,确保向后兼容性的同时提供强大的扩展能力。通过合理使用这些核心概念和优化功能,可以构建出高性能、结构清晰、易于维护的游戏代码。

View File

@@ -33,7 +33,7 @@ Core.update(deltaTime);
### 基础配置
ECS框架提供了灵活的配置选项来满足不同项目需求
ECS框架提供了灵活的配置选项来满足不同项目需求。框架采用融合设计既支持传统的单Scene模式向后兼容也支持高级的多World/多Scene架构
```typescript
import { Core, ICoreConfig } from '@esengine/ecs-framework';
@@ -65,6 +65,31 @@ const config: ICoreConfig = {
const core = Core.create(config);
```
### 架构说明
ECS框架支持两种使用模式
1. **单Scene模式默认向后兼容**
```typescript
// 传统用法,无需任何修改
const scene = new Scene();
Core.setScene(scene);
```
2. **多World模式高级功能**
```typescript
// 启用World管理器支持多World/多Scene架构
Core.enableWorldManager();
const roomWorld = Core.getWorldManager().createWorld('Room_001');
const battleScene = roomWorld.createScene('battle');
```
**使用场景:**
- **单Scene模式**:适合简单游戏、单机游戏、原型开发
- **多World模式**:适合多人游戏服务器、复杂应用、需要场景隔离的项目
> **详细了解World系统**:查看 [场景管理完整指南](scene-management-guide.md) 获取完整的多World架构示例和最佳实践
### 调试功能
ECS框架内置了强大的调试功能支持运行时监控和远程调试
@@ -324,7 +349,7 @@ class CocosRenderSystem extends EntitySystem {
### Node.js后端
```typescript
import { Core, Scene, EntityManager, EntitySystem, Time } from '@esengine/ecs-framework';
import { Core, Scene, EntityManager, EntitySystem, Time, World } from '@esengine/ecs-framework';
class ServerGameManager {
private scene: Scene;
@@ -338,6 +363,7 @@ class ServerGameManager {
Core.create(true); // 启用调试模式
// 完整配置示例: Core.create({ debug: true, enableEntitySystems: true, debugConfig: {...} })
// 单Scene模式简单场景
this.scene = new Scene();
this.scene.name = "ServerScene";
Core.setScene(this.scene);
@@ -418,6 +444,8 @@ const server = new ServerGameManager();
server.start();
```
> **多房间游戏服务器示例**:查看 [场景管理完整指南](scene-management-guide.md#world多场景管理) 了解如何使用多World架构实现复杂的多房间游戏服务器
### 原生浏览器
```typescript

View File

@@ -1,6 +1,6 @@
# 场景管理完整指南
场景Scene是ECS框架中管理游戏对象和系统的核心容器。本指南将详细介绍如何有效地使用场景来构建和管理你的游戏。
场景Scene是ECS框架中管理游戏对象和系统的核心容器。框架采用融合设计既支持传统的单Scene模式向后兼容也支持高级的多World/多Scene架构。本指南将详细介绍如何有效地使用场景来构建和管理你的游戏。
## 场景基础概念
@@ -25,6 +25,47 @@ Core.setScene(gameScene);
> **注意**: `Core.scene = ` 设置方式已被标记为废弃,推荐使用 `Core.setScene()` 方法。新方法提供更好的类型安全性和可预测的激活时序。
### 架构选择指南
ECS框架提供两种使用模式
#### 1. 单Scene模式默认向后兼容
```typescript
// 传统用法,无需任何修改
const scene = new Scene();
Core.setScene(scene);
```
**适用场景:**
- 简单游戏、单机游戏
- 原型开发、快速验证
- 学习ECS架构
- 不需要复杂场景管理的项目
#### 2. 多World模式高级功能
```typescript
// 启用World管理器
Core.enableWorldManager();
const worldManager = Core.getWorldManager();
// 创建多个World每个World可包含多个Scene
const roomWorld = worldManager.createWorld('Room_001');
const battleScene = roomWorld.createScene('battle');
const uiScene = roomWorld.createScene('ui');
roomWorld.start();
roomWorld.setSceneActive('battle', true);
roomWorld.setSceneActive('ui', true);
```
**适用场景:**
- 多人游戏服务器每个房间一个World
- 复杂应用架构(需要场景隔离)
- 需要并发处理多个游戏世界
- 高级场景管理需求
### 场景的生命周期
```typescript
@@ -214,9 +255,374 @@ class GameScene extends Scene {
}
```
## 场景切换和管理
## World多场景管理
### 1. 场景管理器
### 1. World基础使用
对于需要复杂场景管理的项目可以使用World系统
```typescript
import { Core, World, Scene, WorldManager, IGlobalSystem } from '@esengine/ecs-framework';
// 定义全局系统跨Scene的业务逻辑
class NetworkSyncSystem implements IGlobalSystem {
public readonly name = 'NetworkSyncSystem';
public initialize(): void {
console.log('网络同步系统初始化');
}
public update(): void {
// 同步所有Scene的网络状态
this.syncNetworkData();
}
public reset(): void {
// 重置网络连接
}
public destroy(): void {
console.log('网络同步系统销毁');
}
private syncNetworkData(): void {
// 网络数据同步逻辑
}
}
class PlayerManagementSystem implements IGlobalSystem {
public readonly name = 'PlayerManagementSystem';
public initialize(): void {
console.log('玩家管理系统初始化');
}
public update(): void {
// 管理跨Scene的玩家数据
this.managePlayerStates();
}
public reset(): void {
// 重置玩家状态
}
public destroy(): void {
console.log('玩家管理系统销毁');
}
private managePlayerStates(): void {
// 玩家状态管理逻辑
}
}
// 启用World管理功能
Core.enableWorldManager();
const worldManager = Core.getWorldManager();
// 创建游戏房间World
const roomWorld = worldManager.createWorld('GameRoom_001', {
name: 'GameRoom_001',
maxScenes: 5,
autoCleanup: true,
debug: true
});
// 在World中创建多个Scene
const gameScene = roomWorld.createScene('game', new GameScene());
const uiScene = roomWorld.createScene('ui', new UIScene());
const backgroundScene = roomWorld.createScene('background', new BackgroundScene());
// 添加全局系统跨Scene的系统
roomWorld.addGlobalSystem(new NetworkSyncSystem());
roomWorld.addGlobalSystem(new PlayerManagementSystem());
// 启动World并激活Scene
roomWorld.start();
roomWorld.setSceneActive('game', true);
roomWorld.setSceneActive('ui', true);
roomWorld.setSceneActive('background', true);
```
### 2. 多房间游戏服务器示例
```typescript
// 房间管理系统
class RoomManagementSystem implements IGlobalSystem {
public readonly name = 'RoomManagementSystem';
private roomId: string;
constructor(roomId: string) {
this.roomId = roomId;
}
public initialize(): void {
console.log(`房间管理系统初始化: ${this.roomId}`);
}
public update(): void {
// 管理房间状态、玩家进出等
this.manageRoomState();
}
public reset(): void {
// 重置房间状态
}
public destroy(): void {
console.log(`房间管理系统销毁: ${this.roomId}`);
}
private manageRoomState(): void {
// 房间状态管理逻辑
}
}
// 玩家同步系统
class PlayerSyncSystem implements IGlobalSystem {
public readonly name = 'PlayerSyncSystem';
public initialize(): void {
console.log('玩家同步系统初始化');
}
public update(): void {
// 同步房间内所有玩家的状态
this.syncPlayerData();
}
public reset(): void {
// 重置同步状态
}
public destroy(): void {
console.log('玩家同步系统销毁');
}
private syncPlayerData(): void {
// 玩家数据同步逻辑
}
}
class MultiRoomGameServer {
private worldManager: WorldManager;
private rooms: Map<string, World> = new Map();
constructor() {
Core.create({ debug: false });
Core.enableWorldManager();
this.worldManager = Core.getWorldManager();
}
// 创建游戏房间
createRoom(roomId: string): World {
const roomWorld = this.worldManager.createWorld(`Room_${roomId}`, {
name: `GameRoom_${roomId}`,
maxScenes: 3,
autoCleanup: true
});
// 房间内的Scene设置
const gameScene = roomWorld.createScene('game', new ServerGameScene());
const lobbyScene = roomWorld.createScene('lobby', new LobbyScene());
// 设置房间级的全局系统
roomWorld.addGlobalSystem(new RoomManagementSystem(roomId));
roomWorld.addGlobalSystem(new PlayerSyncSystem());
// 启动房间
roomWorld.start();
roomWorld.setSceneActive('lobby', true); // 默认激活大厅
this.rooms.set(roomId, roomWorld);
console.log(`创建房间: ${roomId}`);
return roomWorld;
}
// 开始游戏
startGame(roomId: string): boolean {
const roomWorld = this.rooms.get(roomId);
if (!roomWorld) return false;
// 停用大厅激活游戏Scene
roomWorld.setSceneActive('lobby', false);
roomWorld.setSceneActive('game', true);
console.log(`房间 ${roomId} 开始游戏`);
return true;
}
// 销毁房间
destroyRoom(roomId: string): boolean {
const roomWorld = this.rooms.get(roomId);
if (!roomWorld) return false;
roomWorld.destroy();
this.rooms.delete(roomId);
console.log(`销毁房间: ${roomId}`);
return true;
}
// 获取服务器状态
getServerStats() {
return {
totalRooms: this.rooms.size,
activeWorlds: this.worldManager.getActiveWorlds().length,
rooms: Array.from(this.rooms.keys()).map(roomId => ({
roomId,
world: this.rooms.get(roomId)?.getStatus()
}))
};
}
// 游戏循环
start(): void {
const gameLoop = () => {
const deltaTime = 1000 / 60; // 60 TPS
Core.update(deltaTime / 1000);
setTimeout(gameLoop, deltaTime);
};
gameLoop();
}
}
// 使用示例
const gameServer = new MultiRoomGameServer();
gameServer.start();
// 创建房间
const room1 = gameServer.createRoom('room_001');
const room2 = gameServer.createRoom('room_002');
// 开始游戏
setTimeout(() => {
gameServer.startGame('room_001');
}, 5000);
console.log('服务器状态:', gameServer.getServerStats());
```
### 3. 客户端多Scene管理示例
```typescript
class GameClient {
private worldManager: WorldManager;
private mainWorld: World;
constructor() {
Core.create({ debug: true });
Core.enableWorldManager();
this.worldManager = Core.getWorldManager();
this.setupGameWorld();
}
private setupGameWorld(): void {
// 创建主游戏世界
this.mainWorld = this.worldManager.createWorld('MainWorld', {
name: 'ClientWorld',
maxScenes: 10,
autoCleanup: false // 客户端通常不需要自动清理
});
// 创建不同层级的Scene
this.createGameplayScenes();
this.createUIScenes();
this.createEffectScenes();
// 启动世界
this.mainWorld.start();
this.activateDefaultScenes();
}
private createGameplayScenes(): void {
// 游戏主场景
const gameScene = this.mainWorld.createScene('gameplay', new GameplayScene());
// 背景场景
const backgroundScene = this.mainWorld.createScene('background', new BackgroundScene());
// 特效场景
const effectsScene = this.mainWorld.createScene('effects', new EffectsScene());
}
private createUIScenes(): void {
// 主UI场景
const mainUIScene = this.mainWorld.createScene('mainUI', new MainUIScene());
// 菜单场景
const menuScene = this.mainWorld.createScene('menu', new MenuScene());
// 设置场景
const settingsScene = this.mainWorld.createScene('settings', new SettingsScene());
}
private createEffectScenes(): void {
// 粒子效果场景
const particleScene = this.mainWorld.createScene('particles', new ParticleScene());
// 音效场景
const audioScene = this.mainWorld.createScene('audio', new AudioScene());
}
private activateDefaultScenes(): void {
// 激活基础Scene
this.mainWorld.setSceneActive('background', true);
this.mainWorld.setSceneActive('gameplay', true);
this.mainWorld.setSceneActive('mainUI', true);
this.mainWorld.setSceneActive('particles', true);
this.mainWorld.setSceneActive('audio', true);
// 菜单和设置默认不激活
this.mainWorld.setSceneActive('menu', false);
this.mainWorld.setSceneActive('settings', false);
}
// 切换到菜单
showMenu(): void {
this.mainWorld.setSceneActive('gameplay', false);
this.mainWorld.setSceneActive('menu', true);
}
// 切换回游戏
hideMenu(): void {
this.mainWorld.setSceneActive('menu', false);
this.mainWorld.setSceneActive('gameplay', true);
}
// 显示设置
showSettings(): void {
this.mainWorld.setSceneActive('settings', true);
}
// 隐藏设置
hideSettings(): void {
this.mainWorld.setSceneActive('settings', false);
}
// 获取World状态
getWorldStatus() {
return this.mainWorld.getStatus();
}
}
// 使用示例
const gameClient = new GameClient();
// 显示菜单
gameClient.showMenu();
// 5秒后返回游戏
setTimeout(() => {
gameClient.hideMenu();
}, 5000);
console.log('客户端World状态:', gameClient.getWorldStatus());
```
## 传统场景切换和管理
### 1. 单Scene模式场景管理器
> **注意:** 以下的 SceneManager、TransitionManager 等是自定义的场景管理类示例不是ECS框架提供的内置API。你可以基于这些示例实现自己的场景管理系统。
@@ -731,6 +1137,47 @@ A:
### Q: 多个场景可以同时存在吗?
A: 框架同时只支持一个活跃场景,但可以通过场景栈实现多场景管理(如暂停菜单)。
A:
- **单Scene模式**:框架同时只支持一个活跃场景,但可以通过场景栈实现多场景管理(如暂停菜单)
- **多World模式**每个World可以包含多个同时激活的Scene支持复杂的多场景架构
通过合理使用场景系统,你可以构建出结构清晰、性能优良的游戏架构!
### Q: 什么时候使用World系统
A:
- 多人游戏服务器(每个房间独立管理)
- 需要并发运行多个独立游戏世界
- 复杂的客户端架构游戏层、UI层、特效层分离
- 需要跨Scene的全局系统支持
### Q: World和Scene的性能影响
A:
- **单Scene模式**:最佳性能,适合简单项目
- **多World模式**每个World独立更新合理使用不会显著影响性能
- **建议**:根据项目复杂度选择合适的架构
### Q: 如何从单Scene迁移到多World
A:
```typescript
// 原始单Scene代码
const scene = new Scene();
Core.setScene(scene);
// 迁移到World模式可选
Core.enableWorldManager();
const world = Core.getWorldManager().createWorld('MainWorld');
const scene = world.createScene('main', new Scene());
world.start();
world.setSceneActive('main', true);
```
### Q: World系统的最佳实践
A:
1. **服务器端**每个游戏房间使用独立World
2. **客户端**按功能层级划分Scene游戏、UI、特效
3. **全局系统**将跨Scene的逻辑放在World的全局System中
4. **资源管理**使用World的autoCleanup功能自动清理空闲资源
通过合理选择单Scene或多World架构你可以构建出结构清晰、性能优良的游戏架构

2
package-lock.json generated
View File

@@ -11537,7 +11537,7 @@
},
"packages/core": {
"name": "@esengine/ecs-framework",
"version": "2.1.44",
"version": "2.1.45",
"license": "MIT",
"devDependencies": {
"@rollup/plugin-commonjs": "^28.0.3",

View File

@@ -1,6 +1,6 @@
{
"name": "@esengine/ecs-framework",
"version": "2.1.44",
"version": "2.1.45",
"description": "用于Laya、Cocos Creator等JavaScript游戏引擎的高性能ECS框架",
"main": "bin/index.js",
"types": "bin/index.d.ts",

View File

@@ -6,8 +6,8 @@ import { Time } from './Utils/Time';
import { PerformanceMonitor } from './Utils/PerformanceMonitor';
import { PoolManager } from './Utils/Pool/PoolManager';
import { ECSFluentAPI, createECSAPI } from './ECS/Core/FluentAPI';
import { Scene } from './ECS/Scene';
import { IScene } from './ECS/IScene';
import { WorldManager } from './ECS/WorldManager';
import { DebugManager } from './Utils/Debug';
import { ICoreConfig, IECSDebugConfig } from './Types';
import { BigIntFactory, EnvironmentInfo } from './ECS/Utils/BigIntCompatibility';
@@ -47,6 +47,20 @@ export class Core {
*/
public static paused = false;
/**
* 默认World ID
*
* 用于单Scene模式的默认World标识
*/
private static readonly DEFAULT_WORLD_ID = '__default__';
/**
* 默认Scene ID
*
* 用于单Scene模式的默认Scene标识
*/
private static readonly DEFAULT_SCENE_ID = '__main__';
/**
* 全局核心实例
*/
@@ -71,12 +85,6 @@ export class Core {
*/
public readonly debug: boolean;
/**
* 待切换的场景
*
* 存储下一帧要切换到的场景实例。
*/
public _nextScene: IScene | null = null;
/**
* 全局管理器集合
@@ -113,10 +121,6 @@ export class Core {
*/
public _ecsAPI?: ECSFluentAPI;
/**
* 当前活动场景
*/
public _scene?: IScene;
/**
* 调试管理器
@@ -125,6 +129,13 @@ export class Core {
*/
public _debugManager?: DebugManager;
/**
* World管理器
*
* 管理多个World实例支持多房间/多世界架构。
*/
public _worldManager?: WorldManager;
/**
* Core配置
*/
@@ -194,82 +205,63 @@ export class Core {
}
/**
* 获取当前活动的场景
* 获取当前活动的场景(属性访问器)
*
* @returns 当前场景实例如果没有则返回null
*/
public static get scene(): IScene | null {
if (!this._instance)
return null;
return this._instance._scene || null;
return this.getScene();
}
/**
* 设置当前场景(已废弃
* 获取当前活动的场景(方法调用
*
* @deprecated 请使用 Core.setScene() 方法代替。scene setter 可能导致场景延迟激活的时序问题,
* 而 setScene() 提供更好的类型安全性和可预测的激活时序。
*
* 迁移示例:
* ```typescript
* // 旧方式(已废弃)
* Core.scene = myScene;
*
* // 新方式(推荐)
* Core.setScene(myScene);
* ```
*
* 如果当前没有场景,会立即切换;否则会在下一帧切换。
*
* @param value - 场景实例
* @returns 当前场景实例如果没有则返回null
*/
public static set scene(value: IScene | null) {
if (!value) return;
public static getScene<T extends IScene>(): T | null {
if (!this._instance) {
return null;
}
if (this._instance._scene == null) {
this._instance.setSceneInternal(value);
} else {
this._instance._nextScene = value;
}
// 确保默认World存在
this._instance.ensureDefaultWorld();
const defaultWorld = this._instance._worldManager!.getWorld(this.DEFAULT_WORLD_ID);
return defaultWorld?.getScene(this.DEFAULT_SCENE_ID) as T || null;
}
/**
* 类型安全的场景设置方法(推荐)
*
* 这是设置场景的推荐方法,提供更好的类型安全性和可预测的激活时序。
* 相比于 scene setter此方法能确保场景正确初始化和激活。
*
* 如果当前没有场景,会立即切换;否则会在下一帧切换。
* 设置当前场景
*
* @param scene - 要设置的场景实例
* @returns 设置的场景实例,便于链式调用
*
* @example
* ```typescript
* const myScene = new MyScene();
* Core.setScene(myScene);
*
* // 链式调用
* const scene = Core.setScene(new MyScene()).addSystem(new MySystem());
* ```
*/
public static setScene<T extends IScene>(scene: T): T {
if (this._instance._scene == null) {
this._instance.setSceneInternal(scene);
} else {
this._instance._nextScene = scene;
if (!this._instance) {
throw new Error("Core实例未创建请先调用Core.create()");
}
// 确保默认World存在
this._instance.ensureDefaultWorld();
const defaultWorld = this._instance._worldManager!.getWorld(this.DEFAULT_WORLD_ID)!;
// 移除旧的主Scene如果存在
if (defaultWorld.getScene(this.DEFAULT_SCENE_ID)) {
defaultWorld.removeScene(this.DEFAULT_SCENE_ID);
}
// 添加新Scene到默认World
defaultWorld.createScene(this.DEFAULT_SCENE_ID, scene);
defaultWorld.setSceneActive(this.DEFAULT_SCENE_ID, true);
// 触发场景切换回调
this._instance.onSceneChanged();
return scene;
}
/**
* 类型安全的场景获取方法
*
* @returns 当前场景实例
*/
public static getScene<T extends IScene>(): T | null {
return this._instance?._scene as T || null;
}
/**
* 创建Core实例
@@ -466,15 +458,61 @@ export class Core {
}
/**
* 内部场景设置方法
* 获取WorldManager实例
*
* @param scene - 要设置的场景实例
* @returns WorldManager实例如果未初始化则自动创建
*/
private setSceneInternal(scene: IScene): void {
this._scene = scene;
this.onSceneChanged();
this._scene.initialize();
this._scene.begin();
public static getWorldManager(): WorldManager {
if (!this._instance) {
throw new Error("Core实例未创建请先调用Core.create()");
}
if (!this._instance._worldManager) {
// 多World模式的配置用户主动获取WorldManager
this._instance._worldManager = WorldManager.getInstance({
maxWorlds: 50,
autoCleanup: true,
cleanupInterval: 60000,
debug: this._instance._config.debug
});
}
return this._instance._worldManager;
}
/**
* 启用World管理
*
* 显式启用World功能用于多房间/多世界架构
*/
public static enableWorldManager(): WorldManager {
return this.getWorldManager();
}
/**
* 确保默认World存在
*
* 内部方法用于懒初始化默认World
*/
private ensureDefaultWorld(): void {
if (!this._worldManager) {
this._worldManager = WorldManager.getInstance({
maxWorlds: 1, // 单场景用户只需要1个World
autoCleanup: false, // 单场景不需要自动清理
cleanupInterval: 0, // 禁用清理定时器
debug: this._config.debug
});
}
// 检查默认World是否存在
if (!this._worldManager.getWorld(Core.DEFAULT_WORLD_ID)) {
this._worldManager.createWorld(Core.DEFAULT_WORLD_ID, {
name: 'DefaultWorld',
maxScenes: 1,
autoCleanup: false
});
this._worldManager.setWorldActive(Core.DEFAULT_WORLD_ID, true);
}
}
/**
@@ -485,28 +523,19 @@ export class Core {
public onSceneChanged() {
Time.sceneChanged();
// 获取当前Scene从默认World
const currentScene = Core.getScene();
// 初始化ECS API如果场景支持
if (this._scene && this._scene.querySystem && this._scene.eventSystem) {
this._ecsAPI = createECSAPI(this._scene, this._scene.querySystem, this._scene.eventSystem);
if (currentScene && currentScene.querySystem && currentScene.eventSystem) {
this._ecsAPI = createECSAPI(currentScene, currentScene.querySystem, currentScene.eventSystem);
}
// 延迟调试管理器通知,避免在场景初始化过程中干扰属性
if (this._debugManager) {
// 使用 requestAnimationFrame 确保在场景完全初始化后再收集数据
if (typeof requestAnimationFrame !== 'undefined') {
requestAnimationFrame(() => {
if (this._debugManager) {
this._debugManager.onSceneChanged();
}
queueMicrotask(() => {
this._debugManager?.onSceneChanged();
});
} else {
// 兜底:使用 setTimeout
setTimeout(() => {
if (this._debugManager) {
this._debugManager.onSceneChanged();
}
}, 0);
}
}
}
@@ -567,23 +596,25 @@ export class Core {
// 更新对象池管理器
this._poolManager.update();
// 处理场景切换
if (this._nextScene != null) {
if (this._scene != null)
this._scene.end();
// 更新所有World
if (this._worldManager) {
const worldsStartTime = this._performanceMonitor.startMonitoring('Worlds.update');
const activeWorlds = this._worldManager.getActiveWorlds();
let totalWorldEntities = 0;
this._scene = this._nextScene;
this._nextScene = null;
this.onSceneChanged();
this._scene.begin();
for (const world of activeWorlds) {
// 更新World的全局System
world.updateGlobalSystems();
// 更新World中的所有Scene
world.updateScenes();
// 统计实体数量(用于性能监控)
const worldStats = world.getStats();
totalWorldEntities += worldStats.totalEntities;
}
// 更新当前场景
if (this._scene != null && this._scene.update) {
const sceneStartTime = this._performanceMonitor.startMonitoring('Scene.update');
this._scene.update();
const entityCount = this._scene.entities?.count || 0;
this._performanceMonitor.endMonitoring('Scene.update', sceneStartTime, entityCount);
this._performanceMonitor.endMonitoring('Worlds.update', worldsStartTime, totalWorldEntities);
}
// 更新调试管理器基于FPS的数据发送

View File

@@ -0,0 +1,504 @@
import { IScene } from './IScene';
import { Scene } from './Scene';
import { createLogger } from '../Utils/Logger';
const logger = createLogger('World');
/**
* 全局系统接口
* 全局系统是在World级别运行的系统不依赖特定Scene
*/
export interface IGlobalSystem {
/**
* 系统名称
*/
readonly name: string;
/**
* 初始化系统
*/
initialize?(): void;
/**
* 更新系统
*/
update(deltaTime?: number): void;
/**
* 重置系统
*/
reset?(): void;
/**
* 销毁系统
*/
destroy?(): void;
}
/**
* World配置接口
*/
export interface IWorldConfig {
/**
* World名称
*/
name?: string;
/**
* 是否启用调试模式
*/
debug?: boolean;
/**
* 最大Scene数量限制
*/
maxScenes?: number;
/**
* 是否自动清理空Scene
*/
autoCleanup?: boolean;
}
/**
* World类 - ECS世界管理器
*
* World是Scene的容器每个World可以管理多个Scene。
* 这种设计允许创建独立的游戏世界,如:
* - 游戏房间每个房间一个World
* - 不同的游戏模式
* - 独立的模拟环境
*
* @example
* ```typescript
* // 创建游戏房间的World
* const roomWorld = new World({ name: 'Room_001' });
*
* // 在World中创建Scene
* const gameScene = roomWorld.createScene('game', new Scene());
* const uiScene = roomWorld.createScene('ui', new Scene());
*
* // 更新整个World
* roomWorld.update(deltaTime);
* ```
*/
export class World {
public readonly name: string;
private readonly _config: IWorldConfig;
private readonly _scenes: Map<string, IScene> = new Map();
private readonly _activeScenes: Set<string> = new Set();
private readonly _globalSystems: IGlobalSystem[] = [];
private _isActive: boolean = false;
private _createdAt: number;
constructor(config: IWorldConfig = {}) {
this._config = {
name: 'World',
debug: false,
maxScenes: 10,
autoCleanup: true,
...config
};
this.name = this._config.name!;
this._createdAt = Date.now();
logger.info(`创建World: ${this.name}`);
}
// ===== Scene管理 =====
/**
* 创建并添加Scene到World
*/
public createScene<T extends IScene>(sceneId: string, sceneInstance?: T): T {
if (this._scenes.has(sceneId)) {
throw new Error(`Scene ID '${sceneId}' 已存在于World '${this.name}' 中`);
}
if (this._scenes.size >= this._config.maxScenes!) {
throw new Error(`World '${this.name}' 已达到最大Scene数量限制: ${this._config.maxScenes}`);
}
// 如果没有提供Scene实例创建默认Scene
const scene = sceneInstance || (new Scene() as unknown as T);
// 设置Scene的标识
if ('id' in scene) {
(scene as any).id = sceneId;
}
if ('name' in scene && !scene.name) {
scene.name = sceneId;
}
this._scenes.set(sceneId, scene);
// 初始化Scene
scene.initialize();
logger.info(`在World '${this.name}' 中创建Scene: ${sceneId}`);
return scene;
}
/**
* 移除Scene
*/
public removeScene(sceneId: string): boolean {
const scene = this._scenes.get(sceneId);
if (!scene) {
return false;
}
// 如果Scene正在运行先停止它
if (this._activeScenes.has(sceneId)) {
this.setSceneActive(sceneId, false);
}
// 清理Scene资源
scene.end();
this._scenes.delete(sceneId);
logger.info(`从World '${this.name}' 中移除Scene: ${sceneId}`);
return true;
}
/**
* 获取Scene
*/
public getScene<T extends IScene>(sceneId: string): T | null {
return this._scenes.get(sceneId) as T || null;
}
/**
* 获取所有Scene ID
*/
public getSceneIds(): string[] {
return Array.from(this._scenes.keys());
}
/**
* 获取所有Scene
*/
public getAllScenes(): IScene[] {
return Array.from(this._scenes.values());
}
/**
* 设置Scene激活状态
*/
public setSceneActive(sceneId: string, active: boolean): void {
const scene = this._scenes.get(sceneId);
if (!scene) {
logger.warn(`Scene '${sceneId}' 不存在于World '${this.name}' 中`);
return;
}
if (active) {
this._activeScenes.add(sceneId);
// 启动Scene
if (scene.begin) {
scene.begin();
}
logger.debug(`在World '${this.name}' 中激活Scene: ${sceneId}`);
} else {
this._activeScenes.delete(sceneId);
// 可选择性地停止Scene或者让它继续运行但不更新
logger.debug(`在World '${this.name}' 中停用Scene: ${sceneId}`);
}
}
/**
* 检查Scene是否激活
*/
public isSceneActive(sceneId: string): boolean {
return this._activeScenes.has(sceneId);
}
/**
* 获取活跃Scene数量
*/
public getActiveSceneCount(): number {
return this._activeScenes.size;
}
// ===== 全局System管理 =====
/**
* 添加全局System
* 全局System会在所有激活Scene之前更新
*/
public addGlobalSystem<T extends IGlobalSystem>(system: T): T {
if (this._globalSystems.includes(system)) {
return system;
}
this._globalSystems.push(system);
if (system.initialize) {
system.initialize();
}
logger.debug(`在World '${this.name}' 中添加全局System: ${system.name}`);
return system;
}
/**
* 移除全局System
*/
public removeGlobalSystem(system: IGlobalSystem): boolean {
const index = this._globalSystems.indexOf(system);
if (index === -1) {
return false;
}
this._globalSystems.splice(index, 1);
if (system.reset) {
system.reset();
}
logger.debug(`从World '${this.name}' 中移除全局System: ${system.name}`);
return true;
}
/**
* 获取全局System
*/
public getGlobalSystem<T extends IGlobalSystem>(type: new (...args: any[]) => T): T | null {
for (const system of this._globalSystems) {
if (system instanceof type) {
return system as T;
}
}
return null;
}
// ===== World生命周期 =====
/**
* 启动World
*/
public start(): void {
if (this._isActive) {
return;
}
this._isActive = true;
// 启动所有全局System
for (const system of this._globalSystems) {
if (system.initialize) {
system.initialize();
}
}
logger.info(`启动World: ${this.name}`);
}
/**
* 停止World
*/
public stop(): void {
if (!this._isActive) {
return;
}
// 停止所有Scene
for (const sceneId of this._activeScenes) {
this.setSceneActive(sceneId, false);
}
// 重置所有全局System
for (const system of this._globalSystems) {
if (system.reset) {
system.reset();
}
}
this._isActive = false;
logger.info(`停止World: ${this.name}`);
}
/**
* 更新World中的全局System
* 注意此方法由Core.update()调用,不应直接调用
*/
public updateGlobalSystems(): void {
if (!this._isActive) {
return;
}
// 更新全局System
for (const system of this._globalSystems) {
if (system.update) {
system.update();
}
}
}
/**
* 更新World中的所有激活Scene
* 注意此方法由Core.update()调用,不应直接调用
*/
public updateScenes(): void {
if (!this._isActive) {
return;
}
// 更新所有激活的Scene
for (const sceneId of this._activeScenes) {
const scene = this._scenes.get(sceneId);
if (scene && scene.update) {
scene.update();
}
}
// 自动清理(如果启用)
if (this._config.autoCleanup && this.shouldAutoCleanup()) {
this.cleanup();
}
}
/**
* 销毁World
*/
public destroy(): void {
logger.info(`销毁World: ${this.name}`);
// 停止World
this.stop();
// 销毁所有Scene
const sceneIds = Array.from(this._scenes.keys());
for (const sceneId of sceneIds) {
this.removeScene(sceneId);
}
// 清理全局System
for (const system of this._globalSystems) {
if (system.destroy) {
system.destroy();
} else if (system.reset) {
system.reset();
}
}
this._globalSystems.length = 0;
this._scenes.clear();
this._activeScenes.clear();
}
// ===== 状态信息 =====
/**
* 获取World状态
*/
public getStatus() {
return {
name: this.name,
isActive: this._isActive,
sceneCount: this._scenes.size,
activeSceneCount: this._activeScenes.size,
globalSystemCount: this._globalSystems.length,
createdAt: this._createdAt,
config: { ...this._config },
scenes: Array.from(this._scenes.keys()).map(sceneId => ({
id: sceneId,
isActive: this._activeScenes.has(sceneId),
name: this._scenes.get(sceneId)?.name || sceneId
}))
};
}
/**
* 获取World统计信息
*/
public getStats() {
const stats = {
totalEntities: 0,
totalSystems: this._globalSystems.length,
memoryUsage: 0,
performance: {
averageUpdateTime: 0,
maxUpdateTime: 0
}
};
// 统计所有Scene的实体数量
for (const scene of this._scenes.values()) {
if (scene.entities) {
stats.totalEntities += scene.entities.count;
}
if (scene.systems) {
stats.totalSystems += scene.systems.length;
}
}
return stats;
}
// ===== 私有方法 =====
/**
* 检查是否应该执行自动清理
*/
private shouldAutoCleanup(): boolean {
// 简单的清理策略如果有空Scene且超过5分钟没有实体
const currentTime = Date.now();
const cleanupThreshold = 5 * 60 * 1000; // 5分钟
for (const [sceneId, scene] of this._scenes) {
if (!this._activeScenes.has(sceneId) &&
scene.entities &&
scene.entities.count === 0 &&
(currentTime - this._createdAt) > cleanupThreshold) {
return true;
}
}
return false;
}
/**
* 执行清理操作
*/
private cleanup(): void {
const sceneIds = Array.from(this._scenes.keys());
const currentTime = Date.now();
const cleanupThreshold = 5 * 60 * 1000; // 5分钟
for (const sceneId of sceneIds) {
const scene = this._scenes.get(sceneId);
if (scene &&
!this._activeScenes.has(sceneId) &&
scene.entities &&
scene.entities.count === 0 &&
(currentTime - this._createdAt) > cleanupThreshold) {
this.removeScene(sceneId);
logger.debug(`自动清理空Scene: ${sceneId} from World ${this.name}`);
}
}
}
// ===== 访问器 =====
/**
* 检查World是否激活
*/
public get isActive(): boolean {
return this._isActive;
}
/**
* 获取Scene数量
*/
public get sceneCount(): number {
return this._scenes.size;
}
/**
* 获取创建时间
*/
public get createdAt(): number {
return this._createdAt;
}
}

View File

@@ -0,0 +1,463 @@
import { World, IWorldConfig } from './World';
import { createLogger } from '../Utils/Logger';
const logger = createLogger('WorldManager');
/**
* WorldManager配置接口
*/
export interface IWorldManagerConfig {
/**
* 最大World数量
*/
maxWorlds?: number;
/**
* 是否自动清理空World
*/
autoCleanup?: boolean;
/**
* 清理间隔(毫秒)
*/
cleanupInterval?: number;
/**
* 是否启用调试模式
*/
debug?: boolean;
}
/**
* World管理器 - 管理所有World实例
*
* WorldManager是全局单例负责管理所有World的生命周期。
* 每个World都是独立的ECS环境可以包含多个Scene。
*
* 设计理念:
* - Core负责单Scene的传统ECS管理
* - World负责多Scene的管理和协调
* - WorldManager负责多World的全局管理
*
* @example
* ```typescript
* // 获取全局WorldManager
* const worldManager = WorldManager.getInstance();
*
* // 创建游戏房间World
* const roomWorld = worldManager.createWorld('room_001', {
* name: 'GameRoom_001',
* maxScenes: 5
* });
*
* // 在游戏循环中更新所有World
* worldManager.updateAll(deltaTime);
* ```
*/
export class WorldManager {
private static _instance: WorldManager | null = null;
private readonly _config: IWorldManagerConfig;
private readonly _worlds: Map<string, World> = new Map();
private readonly _activeWorlds: Set<string> = new Set();
private _cleanupTimer: NodeJS.Timeout | null = null;
private _isRunning: boolean = false;
private constructor(config: IWorldManagerConfig = {}) {
this._config = {
maxWorlds: 50,
autoCleanup: true,
cleanupInterval: 30000, // 30秒
debug: false,
...config
};
logger.info('WorldManager已初始化', {
maxWorlds: this._config.maxWorlds,
autoCleanup: this._config.autoCleanup,
cleanupInterval: this._config.cleanupInterval
});
this.startCleanupTimer();
}
/**
* 获取WorldManager单例实例
*/
public static getInstance(config?: IWorldManagerConfig): WorldManager {
if (!this._instance) {
this._instance = new WorldManager(config);
}
return this._instance;
}
/**
* 重置WorldManager实例主要用于测试
*/
public static reset(): void {
if (this._instance) {
this._instance.destroy();
this._instance = null;
}
}
// ===== World管理 =====
/**
* 创建新World
*/
public createWorld(worldId: string, config?: IWorldConfig): World {
if (!worldId || typeof worldId !== 'string' || worldId.trim() === '') {
throw new Error('World ID不能为空');
}
if (this._worlds.has(worldId)) {
throw new Error(`World ID '${worldId}' 已存在`);
}
if (this._worlds.size >= this._config.maxWorlds!) {
throw new Error(`已达到最大World数量限制: ${this._config.maxWorlds}`);
}
const worldConfig: IWorldConfig = {
name: worldId,
debug: this._config.debug,
...config
};
const world = new World(worldConfig);
this._worlds.set(worldId, world);
logger.info(`创建World: ${worldId}`, { config: worldConfig });
return world;
}
/**
* 移除World
*/
public removeWorld(worldId: string): boolean {
const world = this._worlds.get(worldId);
if (!world) {
return false;
}
// 如果World正在运行先停止它
if (this._activeWorlds.has(worldId)) {
this.setWorldActive(worldId, false);
}
// 销毁World
world.destroy();
this._worlds.delete(worldId);
logger.info(`移除World: ${worldId}`);
return true;
}
/**
* 获取World
*/
public getWorld(worldId: string): World | null {
return this._worlds.get(worldId) || null;
}
/**
* 获取所有World ID
*/
public getWorldIds(): string[] {
return Array.from(this._worlds.keys());
}
/**
* 获取所有World
*/
public getAllWorlds(): World[] {
return Array.from(this._worlds.values());
}
/**
* 设置World激活状态
*/
public setWorldActive(worldId: string, active: boolean): void {
const world = this._worlds.get(worldId);
if (!world) {
logger.warn(`World '${worldId}' 不存在`);
return;
}
if (active) {
this._activeWorlds.add(worldId);
world.start();
logger.debug(`激活World: ${worldId}`);
} else {
this._activeWorlds.delete(worldId);
world.stop();
logger.debug(`停用World: ${worldId}`);
}
}
/**
* 检查World是否激活
*/
public isWorldActive(worldId: string): boolean {
return this._activeWorlds.has(worldId);
}
// ===== 批量操作 =====
/**
* 获取所有激活的World
* 注意此方法供Core.update()使用
*/
public getActiveWorlds(): World[] {
const activeWorlds: World[] = [];
for (const worldId of this._activeWorlds) {
const world = this._worlds.get(worldId);
if (world) {
activeWorlds.push(world);
}
}
return activeWorlds;
}
/**
* 启动所有World
*/
public startAll(): void {
this._isRunning = true;
for (const worldId of this._worlds.keys()) {
this.setWorldActive(worldId, true);
}
logger.info('启动所有World');
}
/**
* 停止所有World
*/
public stopAll(): void {
this._isRunning = false;
for (const worldId of this._activeWorlds) {
this.setWorldActive(worldId, false);
}
logger.info('停止所有World');
}
/**
* 查找满足条件的World
*/
public findWorlds(predicate: (world: World) => boolean): World[] {
const results: World[] = [];
for (const world of this._worlds.values()) {
if (predicate(world)) {
results.push(world);
}
}
return results;
}
/**
* 根据名称查找World
*/
public findWorldByName(name: string): World | null {
for (const world of this._worlds.values()) {
if (world.name === name) {
return world;
}
}
return null;
}
// ===== 统计和监控 =====
/**
* 获取WorldManager统计信息
*/
public getStats() {
const stats = {
totalWorlds: this._worlds.size,
activeWorlds: this._activeWorlds.size,
totalScenes: 0,
totalEntities: 0,
totalSystems: 0,
memoryUsage: 0,
isRunning: this._isRunning,
config: { ...this._config },
worlds: [] as any[]
};
for (const [worldId, world] of this._worlds) {
const worldStats = world.getStats();
stats.totalScenes += worldStats.totalSystems; // World的getStats可能需要调整
stats.totalEntities += worldStats.totalEntities;
stats.totalSystems += worldStats.totalSystems;
stats.worlds.push({
id: worldId,
name: world.name,
isActive: this._activeWorlds.has(worldId),
sceneCount: world.sceneCount,
...worldStats
});
}
return stats;
}
/**
* 获取详细状态信息
*/
public getDetailedStatus() {
return {
...this.getStats(),
worlds: Array.from(this._worlds.entries()).map(([worldId, world]) => ({
id: worldId,
isActive: this._activeWorlds.has(worldId),
status: world.getStatus()
}))
};
}
// ===== 生命周期管理 =====
/**
* 清理空World
*/
public cleanup(): number {
const worldsToRemove: string[] = [];
for (const [worldId, world] of this._worlds) {
if (this.shouldCleanupWorld(world)) {
worldsToRemove.push(worldId);
}
}
for (const worldId of worldsToRemove) {
this.removeWorld(worldId);
}
if (worldsToRemove.length > 0) {
logger.debug(`清理了 ${worldsToRemove.length} 个World`);
}
return worldsToRemove.length;
}
/**
* 销毁WorldManager
*/
public destroy(): void {
logger.info('正在销毁WorldManager...');
// 停止清理定时器
this.stopCleanupTimer();
// 停止所有World
this.stopAll();
// 销毁所有World
const worldIds = Array.from(this._worlds.keys());
for (const worldId of worldIds) {
this.removeWorld(worldId);
}
this._worlds.clear();
this._activeWorlds.clear();
this._isRunning = false;
logger.info('WorldManager已销毁');
}
// ===== 私有方法 =====
/**
* 启动清理定时器
*/
private startCleanupTimer(): void {
if (!this._config.autoCleanup || this._cleanupTimer) {
return;
}
this._cleanupTimer = setInterval(() => {
this.cleanup();
}, this._config.cleanupInterval);
logger.debug(`启动World清理定时器间隔: ${this._config.cleanupInterval}ms`);
}
/**
* 停止清理定时器
*/
private stopCleanupTimer(): void {
if (this._cleanupTimer) {
clearInterval(this._cleanupTimer);
this._cleanupTimer = null;
logger.debug('停止World清理定时器');
}
}
/**
* 判断World是否应该被清理
*/
private shouldCleanupWorld(world: World): boolean {
// 清理策略:
// 1. World未激活
// 2. 没有Scene或所有Scene都是空的
// 3. 创建时间超过10分钟
if (world.isActive) {
return false;
}
if (world.sceneCount === 0) {
const age = Date.now() - world.createdAt;
return age > 10 * 60 * 1000; // 10分钟
}
// 检查是否所有Scene都是空的
const allScenes = world.getAllScenes();
const hasEntities = allScenes.some(scene =>
scene.entities && scene.entities.count > 0
);
if (!hasEntities) {
const age = Date.now() - world.createdAt;
return age > 10 * 60 * 1000; // 10分钟
}
return false;
}
// ===== 访问器 =====
/**
* 获取World总数
*/
public get worldCount(): number {
return this._worlds.size;
}
/**
* 获取激活World数量
*/
public get activeWorldCount(): number {
return this._activeWorlds.size;
}
/**
* 检查是否正在运行
*/
public get isRunning(): boolean {
return this._isRunning;
}
/**
* 获取配置
*/
public get config(): IWorldManagerConfig {
return { ...this._config };
}
}

View File

@@ -6,6 +6,8 @@ export * from './Utils';
export * from './Decorators';
export { Scene } from './Scene';
export { IScene, ISceneFactory, ISceneConfig } from './IScene';
export { World, IWorldConfig } from './World';
export { WorldManager, IWorldManagerConfig } from './WorldManager';
export { EntityManager, EntityQueryBuilder } from './Core/EntityManager';
export * from './Core/Events';
export * from './Core/Query';

View File

@@ -0,0 +1,589 @@
import { Core } from '../../../src/Core';
import { Scene } from '../../../src/ECS/Scene';
import { World, IGlobalSystem } from '../../../src/ECS/World';
import { WorldManager } from '../../../src/ECS/WorldManager';
import { EntitySystem } from '../../../src/ECS/Systems/EntitySystem';
import { Component } from '../../../src/ECS/Component';
import { Matcher } from '../../../src/ECS/Utils/Matcher';
import { Entity } from '../../../src/ECS/Entity';
// 测试用组件
class TestComponent extends Component {
public value: number = 0;
constructor(value: number = 0) {
super();
this.value = value;
}
public reset(): void {
this.value = 0;
}
}
class NetworkComponent extends Component {
public playerId: string;
constructor(playerId: string) {
super();
this.playerId = playerId;
}
public reset(): void {
this.playerId = '';
}
}
// 测试用系统
class TestGlobalSystem extends EntitySystem {
public processedEntities: Entity[] = [];
public updateCount: number = 0;
constructor() {
super(Matcher.empty().all(TestComponent));
}
protected override process(entities: Entity[]): void {
this.processedEntities = [...entities];
this.updateCount++;
}
}
// 正确的全局系统实现
class NetworkSyncGlobalSystem implements IGlobalSystem {
public readonly name = 'NetworkSyncSystem';
public updateCount: number = 0;
public initialize(): void {
// 初始化网络连接等
}
public update(): void {
this.updateCount++;
// 同步网络数据等全局逻辑
}
public reset(): void {
this.updateCount = 0;
}
public destroy(): void {
// 清理网络连接等
}
}
// Scene级别的EntitySystem正确的用法
class NetworkSyncSystem extends EntitySystem {
public syncCount: number = 0;
constructor() {
super(Matcher.empty().all(NetworkComponent));
}
protected override process(entities: Entity[]): void {
this.syncCount++;
}
}
// World级别的网络同步全局系统
class NetworkGlobalSystem implements IGlobalSystem {
public readonly name = 'NetworkGlobalSystem';
public syncCount: number = 0;
public initialize(): void {
// 初始化网络连接
}
public update(): void {
this.syncCount++;
// 全局网络同步逻辑
}
public reset(): void {
this.syncCount = 0;
}
public destroy(): void {
// 清理网络连接
}
}
// 测试用Scene
class TestScene extends Scene {
public updateCallCount: number = 0;
public override update(): void {
super.update();
this.updateCallCount++;
}
}
describe('World与Core集成测试', () => {
beforeEach(() => {
// 重置Core和WorldManager
if ((Core as any)._instance) {
(Core as any)._instance = null;
}
WorldManager['_instance'] = null;
});
afterEach(() => {
// 清理资源
if ((Core as any)._instance) {
const worldManager = Core.getWorldManager?.();
if (worldManager) {
const worldIds = worldManager.getWorldIds();
worldIds.forEach(id => {
worldManager.removeWorld(id);
});
}
(Core as any)._instance = null;
}
WorldManager['_instance'] = null;
});
describe('融合设计基础功能', () => {
test('单Scene模式应该保持向后兼容', () => {
Core.create({ debug: false });
// 传统单Scene用法
const scene = new Scene();
scene.name = 'TestScene';
Core.setScene(scene);
const retrievedScene = Core.getScene();
expect(retrievedScene).toBe(scene);
expect(retrievedScene?.name).toBe('TestScene');
});
test('启用WorldManager后应该支持多World功能', () => {
Core.create({ debug: false });
Core.enableWorldManager();
const worldManager = Core.getWorldManager();
expect(worldManager).toBeDefined();
const world = worldManager.createWorld('TestWorld');
expect(world).toBeDefined();
expect(world.name).toBe('TestWorld');
});
test('getWorldManager应该自动创建WorldManager', () => {
Core.create({ debug: false });
// 获取WorldManager会自动创建实例
const worldManager = Core.getWorldManager();
expect(worldManager).toBeDefined();
// 多次获取应该返回同一个实例
const worldManager2 = Core.getWorldManager();
expect(worldManager2).toBe(worldManager);
});
test('单Scene模式下Core.update应该正常工作', () => {
Core.create({ debug: false });
const scene = new TestScene();
Core.setScene(scene);
// 模拟更新
Core.update(0.016);
expect(scene.updateCallCount).toBeGreaterThan(0);
});
});
describe('默认World机制', () => {
test('设置Scene应该自动创建默认World', () => {
Core.create({ debug: false });
const scene = new Scene();
Core.setScene(scene);
// 启用WorldManager后应该能看到默认World
Core.enableWorldManager();
const worldManager = Core.getWorldManager();
expect(worldManager.getWorld('__default__')).toBeDefined();
const defaultWorld = worldManager.getWorld('__default__');
expect(defaultWorld).toBeDefined();
expect(defaultWorld?.getScene('__main__')).toBe(scene);
});
test('默认World的Scene应该正确激活', () => {
Core.create({ debug: false });
const scene = new Scene();
Core.setScene(scene);
Core.enableWorldManager();
const worldManager = Core.getWorldManager();
const defaultWorld = worldManager.getWorld('__default__');
expect(defaultWorld?.isSceneActive('__main__')).toBe(true);
});
test('替换默认Scene应该正确处理', () => {
Core.create({ debug: false });
const scene1 = new Scene();
scene1.name = 'Scene1';
Core.setScene(scene1);
const scene2 = new Scene();
scene2.name = 'Scene2';
Core.setScene(scene2);
const currentScene = Core.getScene();
expect(currentScene).toBe(scene2);
expect(currentScene?.name).toBe('Scene2');
});
});
describe('多World更新机制', () => {
test('Core.update应该更新所有活跃World', () => {
Core.create({ debug: false });
Core.enableWorldManager();
const worldManager = Core.getWorldManager();
// 创建多个World
const world1 = worldManager.createWorld('World1');
const world2 = worldManager.createWorld('World2');
const world3 = worldManager.createWorld('World3');
// 为每个World创建Scene和System
const scene1 = world1.createScene('scene1', new TestScene());
const scene2 = world2.createScene('scene2', new TestScene());
const scene3 = world3.createScene('scene3', new TestScene());
// 启动部分World
worldManager.setWorldActive('World1', true);
worldManager.setWorldActive('World2', true);
// world3保持未启动
world1.setSceneActive('scene1', true);
world2.setSceneActive('scene2', true);
// 执行更新
Core.update(0.016);
// 检查只有激活的World被更新
expect(scene1.updateCallCount).toBeGreaterThan(0);
expect(scene2.updateCallCount).toBeGreaterThan(0);
expect(scene3.updateCallCount).toBe(0);
});
test('全局系统应该在Scene更新前执行', () => {
Core.create({ debug: false });
Core.enableWorldManager();
const worldManager = Core.getWorldManager();
const world = worldManager.createWorld('TestWorld');
// 添加正确设计的全局系统业务逻辑系统不是EntitySystem
const globalSystem = new NetworkSyncGlobalSystem();
world.addGlobalSystem(globalSystem);
// 创建Scene
const scene = world.createScene('testScene');
worldManager.setWorldActive('TestWorld', true);
world.setSceneActive('testScene', true);
// 执行更新
Core.update(0.016);
// 验证全局System被正确更新
expect(globalSystem.updateCount).toBeGreaterThan(0);
});
});
describe('多房间游戏服务器场景', () => {
test('多个游戏房间应该独立运行', () => {
Core.create({ debug: false });
Core.enableWorldManager();
const worldManager = Core.getWorldManager();
// 创建两个游戏房间
const room1 = worldManager.createWorld('Room_001');
const room2 = worldManager.createWorld('Room_002');
// 为每个房间设置Scene
const gameScene1 = room1.createScene('game');
const gameScene2 = room2.createScene('game');
// 为每个房间添加全局网络系统
const netSystem1 = new NetworkGlobalSystem();
const netSystem2 = new NetworkGlobalSystem();
room1.addGlobalSystem(netSystem1);
room2.addGlobalSystem(netSystem2);
// 在每个房间创建玩家
const player1 = gameScene1.createEntity('Player1');
player1.addComponent(new NetworkComponent('player_123'));
const player2 = gameScene2.createEntity('Player2');
player2.addComponent(new NetworkComponent('player_456'));
// 启动房间
worldManager.setWorldActive('Room_001', true);
worldManager.setWorldActive('Room_002', true);
room1.setSceneActive('game', true);
room2.setSceneActive('game', true);
// 模拟游戏循环
for (let i = 0; i < 5; i++) {
Core.update(0.016);
}
// 验证每个房间独立运行
expect(netSystem1.syncCount).toBeGreaterThan(0);
expect(netSystem2.syncCount).toBeGreaterThan(0);
expect(room1.getActiveSceneCount()).toBe(1);
expect(room2.getActiveSceneCount()).toBe(1);
});
test('房间销毁应该完全清理资源', () => {
Core.create({ debug: false });
Core.enableWorldManager();
const worldManager = Core.getWorldManager();
// 创建房间
const room = worldManager.createWorld('TempRoom');
const scene = room.createScene('game');
// 添加内容
for (let i = 0; i < 10; i++) {
const entity = scene.createEntity(`Entity${i}`);
entity.addComponent(new TestComponent(i));
}
room.addGlobalSystem(new NetworkSyncGlobalSystem());
worldManager.setWorldActive('TempRoom', true);
room.setSceneActive('game', true);
// 验证房间正常运行
Core.update(0.016);
const beforeDestroy = worldManager.getStats();
expect(beforeDestroy.totalWorlds).toBe(1);
expect(beforeDestroy.activeWorlds).toBe(1);
// 销毁房间
worldManager.removeWorld('TempRoom');
const afterDestroy = worldManager.getStats();
expect(afterDestroy.totalWorlds).toBe(0);
expect(afterDestroy.activeWorlds).toBe(0);
});
});
describe('客户端多层Scene架构', () => {
test('分层Scene应该同时运行', () => {
Core.create({ debug: false });
Core.enableWorldManager();
const worldManager = Core.getWorldManager();
const clientWorld = worldManager.createWorld('ClientWorld');
// 创建不同层的Scene
const gameplayScene = clientWorld.createScene('gameplay', new TestScene());
const uiScene = clientWorld.createScene('ui', new TestScene());
const effectsScene = clientWorld.createScene('effects', new TestScene());
// 启动世界并激活所有Scene
worldManager.setWorldActive('ClientWorld', true);
clientWorld.setSceneActive('gameplay', true);
clientWorld.setSceneActive('ui', true);
clientWorld.setSceneActive('effects', true);
// 执行更新
Core.update(0.016);
// 验证所有Scene都被更新
expect(gameplayScene.updateCallCount).toBeGreaterThan(0);
expect(uiScene.updateCallCount).toBeGreaterThan(0);
expect(effectsScene.updateCallCount).toBeGreaterThan(0);
});
test('Scene的动态激活和停用', () => {
Core.create({ debug: false });
Core.enableWorldManager();
const worldManager = Core.getWorldManager();
const world = worldManager.createWorld('DynamicWorld');
const gameScene = world.createScene('game', new TestScene());
const menuScene = world.createScene('menu', new TestScene());
worldManager.setWorldActive('DynamicWorld', true);
// 初始状态只有游戏Scene激活
world.setSceneActive('game', true);
world.setSceneActive('menu', false);
Core.update(0.016);
const gameCount1 = gameScene.updateCallCount;
const menuCount1 = menuScene.updateCallCount;
// 切换到菜单
world.setSceneActive('game', false);
world.setSceneActive('menu', true);
Core.update(0.016);
const gameCount2 = gameScene.updateCallCount;
const menuCount2 = menuScene.updateCallCount;
// 验证Scene状态切换
expect(gameCount2).toBe(gameCount1); // 游戏Scene停止更新
expect(menuCount2).toBeGreaterThan(menuCount1); // 菜单Scene开始更新
});
});
describe('性能和稳定性', () => {
test('大量World和Scene应该稳定运行', () => {
Core.create({ debug: false });
Core.enableWorldManager();
const worldManager = Core.getWorldManager();
const worldCount = 20;
const scenePerWorld = 3;
// 创建大量World和Scene
for (let i = 0; i < worldCount; i++) {
const world = worldManager.createWorld(`World${i}`);
for (let j = 0; j < scenePerWorld; j++) {
const scene = world.createScene(`Scene${j}`, new TestScene());
// 添加一些实体
for (let k = 0; k < 5; k++) {
const entity = scene.createEntity(`Entity${k}`);
entity.addComponent(new TestComponent(k));
}
world.setSceneActive(`Scene${j}`, true);
}
worldManager.setWorldActive(`World${i}`, true);
}
// 验证所有资源创建成功
expect(worldManager.getWorldIds()).toHaveLength(worldCount);
expect(worldManager.getActiveWorlds()).toHaveLength(worldCount);
// 执行多次更新测试稳定性
for (let i = 0; i < 10; i++) {
expect(() => {
Core.update(0.016);
}).not.toThrow();
}
// 验证更新正常工作
const activeWorlds = worldManager.getActiveWorlds();
activeWorlds.forEach(world => {
const scenes = world.getAllScenes();
scenes.forEach(scene => {
if (scene instanceof TestScene && world.isSceneActive(scene.name)) {
expect(scene.updateCallCount).toBeGreaterThan(0);
}
});
});
});
test('频繁的World创建和销毁应该不影响性能', () => {
Core.create({ debug: false });
Core.enableWorldManager();
const worldManager = Core.getWorldManager();
// 频繁创建和销毁World
for (let cycle = 0; cycle < 10; cycle++) {
// 创建批次World
const worldIds: string[] = [];
for (let i = 0; i < 5; i++) {
const worldId = `Cycle${cycle}_World${i}`;
worldIds.push(worldId);
const world = worldManager.createWorld(worldId);
const scene = world.createScene('test');
scene.createEntity('entity');
worldManager.setWorldActive(worldId, true);
world.setSceneActive('test', true);
}
// 更新一次
Core.update(0.016);
// 销毁批次World
worldIds.forEach(id => {
worldManager.removeWorld(id);
});
// 验证清理完成
expect(worldManager.getWorldIds()).toHaveLength(0);
expect(worldManager.getActiveWorlds()).toHaveLength(0);
}
});
});
describe('错误处理和边界情况', () => {
test('Core未初始化时操作应该抛出合适错误', () => {
// getScene 会返回 null 而不是抛出错误
expect(Core.getScene()).toBeNull();
expect(() => {
Core.setScene(new Scene());
}).toThrow();
});
test('在World销毁后继续操作应该安全', () => {
Core.create({ debug: false });
Core.enableWorldManager();
const worldManager = Core.getWorldManager();
const world = worldManager.createWorld('DestroyTest');
worldManager.setWorldActive('DestroyTest', true);
worldManager.removeWorld('DestroyTest');
// 对已销毁的World进行操作应该不会崩溃
expect(() => {
world.updateGlobalSystems();
world.updateScenes();
}).not.toThrow();
});
test('混合使用单Scene和多World模式', () => {
Core.create({ debug: false });
// 直接启用WorldManager避免先使用单Scene创建限制性配置
const worldManager = Core.getWorldManager();
// 然后使用单Scene模式
const singleScene = new Scene();
Core.setScene(singleScene);
// 验证默认World被创建
expect(worldManager.getWorld('__default__')).toBeDefined();
// 创建额外的World
const extraWorld = worldManager.createWorld('ExtraWorld');
worldManager.setWorldActive('ExtraWorld', true);
// 两种模式应该能共存
expect(() => {
Core.update(0.016);
}).not.toThrow();
});
});
});

View File

@@ -0,0 +1,466 @@
import { World, IWorldConfig, IGlobalSystem } from '../../src/ECS/World';
import { Scene } from '../../src/ECS/Scene';
import { EntitySystem } from '../../src/ECS/Systems/EntitySystem';
import { Entity } from '../../src/ECS/Entity';
import { Component } from '../../src/ECS/Component';
import { Matcher } from '../../src/ECS/Utils/Matcher';
// 测试用组件
class TestComponent extends Component {
public value: number = 0;
constructor(value: number = 0) {
super();
this.value = value;
}
}
class PlayerComponent extends Component {
public playerId: string;
constructor(playerId: string) {
super();
this.playerId = playerId;
}
}
// 测试用全局系统
class TestGlobalSystem implements IGlobalSystem {
public readonly name = 'TestGlobalSystem';
public updateCount: number = 0;
public initialize(): void {
// 初始化逻辑
}
public update(): void {
this.updateCount++;
}
public reset(): void {
this.updateCount = 0;
}
public destroy(): void {
// 销毁逻辑
}
}
class TestSceneSystem extends EntitySystem {
public updateCount = 0;
constructor() {
super(Matcher.empty().all(PlayerComponent));
}
protected override process(): void {
this.updateCount++;
}
}
// 测试用Scene
class TestScene extends Scene {
public initializeCalled = false;
public beginCalled = false;
public endCalled = false;
public override initialize(): void {
this.initializeCalled = true;
super.initialize();
}
public override begin(): void {
this.beginCalled = true;
super.begin();
}
public override end(): void {
this.endCalled = true;
super.end();
}
}
describe('World', () => {
let world: World;
beforeEach(() => {
world = new World({ name: 'TestWorld' });
});
afterEach(() => {
if (world) {
world.destroy();
}
});
describe('基础功能', () => {
test('创建World时应该设置正确的配置', () => {
const config: IWorldConfig = {
name: 'GameWorld',
debug: true,
maxScenes: 5,
autoCleanup: false
};
const testWorld = new World(config);
expect(testWorld.name).toBe('GameWorld');
expect(testWorld.sceneCount).toBe(0);
expect(testWorld.isActive).toBe(false);
expect(testWorld.createdAt).toBeGreaterThan(0);
testWorld.destroy();
});
test('默认配置应该正确', () => {
const defaultWorld = new World();
expect(defaultWorld.name).toBe('World');
expect(defaultWorld.sceneCount).toBe(0);
expect(defaultWorld.isActive).toBe(false);
defaultWorld.destroy();
});
});
describe('Scene管理', () => {
test('创建Scene应该成功', () => {
const scene = world.createScene('test-scene');
expect(scene).toBeDefined();
expect(world.sceneCount).toBe(1);
expect(world.getSceneIds()).toContain('test-scene');
});
test('创建Scene时传入自定义Scene实例', () => {
const customScene = new TestScene();
const scene = world.createScene('custom-scene', customScene);
expect(scene).toBe(customScene);
expect(scene.initializeCalled).toBe(true);
expect(world.sceneCount).toBe(1);
});
test('重复的Scene ID应该抛出错误', () => {
world.createScene('duplicate');
expect(() => {
world.createScene('duplicate');
}).toThrow("Scene ID 'duplicate' 已存在于World 'TestWorld' 中");
});
test('超出最大Scene数量限制应该抛出错误', () => {
const limitedWorld = new World({ maxScenes: 2 });
limitedWorld.createScene('scene1');
limitedWorld.createScene('scene2');
expect(() => {
limitedWorld.createScene('scene3');
}).toThrow("World 'World' 已达到最大Scene数量限制: 2");
limitedWorld.destroy();
});
test('获取Scene应该正确', () => {
const scene = world.createScene('get-test');
const retrievedScene = world.getScene('get-test');
expect(retrievedScene).toBe(scene);
});
test('获取不存在的Scene应该返回null', () => {
const scene = world.getScene('non-existent');
expect(scene).toBeNull();
});
test('移除Scene应该正确清理', () => {
const testScene = new TestScene();
world.createScene('remove-test', testScene);
world.setSceneActive('remove-test', true);
const removed = world.removeScene('remove-test');
expect(removed).toBe(true);
expect(world.sceneCount).toBe(0);
expect(world.getScene('remove-test')).toBeNull();
expect(testScene.endCalled).toBe(true);
});
test('移除不存在的Scene应该返回false', () => {
const removed = world.removeScene('non-existent');
expect(removed).toBe(false);
});
test('获取所有Scene应该正确', () => {
const scene1 = world.createScene('scene1');
const scene2 = world.createScene('scene2');
const allScenes = world.getAllScenes();
expect(allScenes).toHaveLength(2);
expect(allScenes).toContain(scene1);
expect(allScenes).toContain(scene2);
});
});
describe('Scene激活管理', () => {
test('激活Scene应该正确', () => {
const testScene = new TestScene();
world.createScene('active-test', testScene);
world.setSceneActive('active-test', true);
expect(world.isSceneActive('active-test')).toBe(true);
expect(world.getActiveSceneCount()).toBe(1);
expect(testScene.beginCalled).toBe(true);
});
test('停用Scene应该正确', () => {
world.createScene('deactive-test');
world.setSceneActive('deactive-test', true);
world.setSceneActive('deactive-test', false);
expect(world.isSceneActive('deactive-test')).toBe(false);
expect(world.getActiveSceneCount()).toBe(0);
});
test('激活不存在的Scene应该记录警告', () => {
const consoleSpy = jest.spyOn(console, 'warn').mockImplementation();
world.setSceneActive('non-existent', true);
// 注意:这里需要检查具体的日志实现,可能需要调整
consoleSpy.mockRestore();
});
});
describe('全局System管理', () => {
test('添加全局System应该成功', () => {
const globalSystem = new TestGlobalSystem();
const addedSystem = world.addGlobalSystem(globalSystem);
expect(addedSystem).toBe(globalSystem);
expect(world.getGlobalSystem(TestGlobalSystem)).toBe(globalSystem);
});
test('重复添加相同System应该返回原System', () => {
const globalSystem = new TestGlobalSystem();
const firstAdd = world.addGlobalSystem(globalSystem);
const secondAdd = world.addGlobalSystem(globalSystem);
expect(firstAdd).toBe(secondAdd);
expect(firstAdd).toBe(globalSystem);
});
test('移除全局System应该成功', () => {
const globalSystem = new TestGlobalSystem();
world.addGlobalSystem(globalSystem);
const removed = world.removeGlobalSystem(globalSystem);
expect(removed).toBe(true);
expect(world.getGlobalSystem(TestGlobalSystem)).toBeNull();
});
test('移除不存在的System应该返回false', () => {
const globalSystem = new TestGlobalSystem();
const removed = world.removeGlobalSystem(globalSystem);
expect(removed).toBe(false);
});
test('获取不存在的System类型应该返回null', () => {
const system = world.getGlobalSystem(TestGlobalSystem);
expect(system).toBeNull();
});
});
describe('World生命周期', () => {
test('启动World应该正确', () => {
const globalSystem = new TestGlobalSystem();
world.addGlobalSystem(globalSystem);
world.start();
expect(world.isActive).toBe(true);
});
test('重复启动World应该无效果', () => {
world.start();
const firstActive = world.isActive;
world.start();
expect(world.isActive).toBe(firstActive);
});
test('停止World应该停用所有Scene', () => {
const testScene = new TestScene();
world.createScene('stop-test', testScene);
world.setSceneActive('stop-test', true);
world.start();
world.stop();
expect(world.isActive).toBe(false);
expect(world.isSceneActive('stop-test')).toBe(false);
});
test('销毁World应该清理所有资源', () => {
const testScene = new TestScene();
const globalSystem = new TestGlobalSystem();
world.createScene('destroy-test', testScene);
world.addGlobalSystem(globalSystem);
world.start();
world.destroy();
expect(world.sceneCount).toBe(0);
expect(world.isActive).toBe(false);
expect(testScene.endCalled).toBe(true);
});
});
describe('更新逻辑', () => {
test('updateGlobalSystems应该更新全局系统', () => {
const globalSystem = new TestGlobalSystem();
world.addGlobalSystem(globalSystem);
world.start();
// 创建测试Scene
const scene = world.createScene('update-test');
world.setSceneActive('update-test', true);
// 直接测试全局系统更新
world.updateGlobalSystems();
// 验证全局System被正确调用
expect(globalSystem.updateCount).toBeGreaterThan(0);
});
test('未激活的World不应该更新', () => {
const globalSystem = new TestGlobalSystem();
world.addGlobalSystem(globalSystem);
// 不启动World
world.updateGlobalSystems();
expect(globalSystem.updateCount).toBe(0);
});
test('updateScenes应该更新激活的Scene', () => {
const scene1 = world.createScene('scene1');
const scene2 = world.createScene('scene2');
scene1.addEntityProcessor(new TestSceneSystem());
scene2.addEntityProcessor(new TestSceneSystem());
world.start();
world.setSceneActive('scene1', true);
// scene2保持未激活
world.updateScenes();
// 这里需要根据具体的Scene更新实现来验证
// 由于Scene.update()的具体实现可能不同,这里主要测试调用不出错
expect(() => world.updateScenes()).not.toThrow();
});
});
describe('状态和统计', () => {
test('获取World状态应该正确', () => {
world.createScene('status-scene1');
world.createScene('status-scene2');
world.setSceneActive('status-scene1', true);
world.addGlobalSystem(new TestGlobalSystem());
world.start();
const status = world.getStatus();
expect(status.name).toBe('TestWorld');
expect(status.isActive).toBe(true);
expect(status.sceneCount).toBe(2);
expect(status.activeSceneCount).toBe(1);
expect(status.globalSystemCount).toBe(1);
expect(status.createdAt).toBeGreaterThan(0);
expect(status.scenes).toHaveLength(2);
const activeScene = status.scenes.find(s => s.id === 'status-scene1');
expect(activeScene?.isActive).toBe(true);
const inactiveScene = status.scenes.find(s => s.id === 'status-scene2');
expect(inactiveScene?.isActive).toBe(false);
});
test('获取World统计应该包含基本信息', () => {
world.addGlobalSystem(new TestGlobalSystem());
const scene = world.createScene('stats-scene');
const entity = scene.createEntity('stats-entity');
entity.addComponent(new TestComponent());
const stats = world.getStats();
expect(stats).toHaveProperty('totalEntities');
expect(stats).toHaveProperty('totalSystems');
expect(stats).toHaveProperty('memoryUsage');
expect(stats).toHaveProperty('performance');
expect(stats.totalSystems).toBeGreaterThanOrEqual(1);
});
});
describe('自动清理功能', () => {
test('自动清理应该移除空闲Scene', async () => {
// 创建一个启用自动清理的World
const autoCleanWorld = new World({
name: 'AutoCleanWorld',
autoCleanup: true,
maxScenes: 10
});
// 创建一个空Scene
autoCleanWorld.createScene('empty-scene');
autoCleanWorld.start();
// 手动触发清理检查
autoCleanWorld.updateScenes();
// 由于清理策略基于时间,这里主要测试不会出错
expect(() => autoCleanWorld.updateScenes()).not.toThrow();
autoCleanWorld.destroy();
});
});
describe('错误处理', () => {
test('Scene ID为空时应该创建默认ID', () => {
expect(() => {
world.createScene('');
}).not.toThrow();
});
test('极限情况下的资源管理', () => {
// 创建大量Scene
for (let i = 0; i < 5; i++) {
world.createScene(`scene_${i}`);
world.setSceneActive(`scene_${i}`, true);
}
// 添加多个全局System
for (let i = 0; i < 3; i++) {
world.addGlobalSystem(new TestGlobalSystem());
}
world.start();
// 测试批量清理
expect(() => world.destroy()).not.toThrow();
});
});
});

View File

@@ -0,0 +1,464 @@
import { WorldManager, IWorldManagerConfig } from '../../src/ECS/WorldManager';
import { World, IWorldConfig } from '../../src/ECS/World';
import { Scene } from '../../src/ECS/Scene';
import { EntitySystem } from '../../src/ECS/Systems/EntitySystem';
import { Component } from '../../src/ECS/Component';
import { Matcher } from '../../src/ECS/Utils/Matcher';
// 测试用组件
class TestComponent extends Component {
public value: number = 0;
constructor(value: number = 0) {
super();
this.value = value;
}
}
// 测试用全局系统
class TestGlobalSystem {
public readonly name = 'TestGlobalSystem';
public updateCount: number = 0;
public initialize(): void {
// 初始化
}
public update(): void {
this.updateCount++;
}
public reset(): void {
this.updateCount = 0;
}
public destroy(): void {
// 销毁
}
}
describe('WorldManager', () => {
let worldManager: WorldManager;
beforeEach(() => {
// 重置单例
WorldManager['_instance'] = null;
worldManager = WorldManager.getInstance();
});
afterEach(() => {
// 清理所有World
if (worldManager) {
const worldIds = worldManager.getWorldIds();
worldIds.forEach(id => {
worldManager.removeWorld(id);
});
// 清理定时器
worldManager.destroy();
}
WorldManager['_instance'] = null;
});
describe('单例模式', () => {
test('获取实例应该返回相同的实例', () => {
const instance1 = WorldManager.getInstance();
const instance2 = WorldManager.getInstance();
expect(instance1).toBe(instance2);
});
test('使用配置创建实例应该正确', () => {
WorldManager['_instance'] = null;
const config: IWorldManagerConfig = {
maxWorlds: 10,
autoCleanup: true,
debug: false
};
const instance = WorldManager.getInstance(config);
expect(instance).toBeDefined();
expect(instance).toBe(WorldManager.getInstance());
});
});
describe('World管理', () => {
test('创建World应该成功', () => {
const world = worldManager.createWorld('test-world');
expect(world).toBeDefined();
expect(world.name).toBe('test-world');
expect(worldManager.getWorld('test-world')).toBeDefined();
expect(worldManager.getWorldIds()).toContain('test-world');
});
test('创建World时传入配置应该正确', () => {
const worldConfig: IWorldConfig = {
name: 'ConfiguredWorld',
debug: true,
maxScenes: 5,
autoCleanup: false
};
const world = worldManager.createWorld('configured-world', worldConfig);
expect(world.name).toBe('ConfiguredWorld');
});
test('重复的World ID应该抛出错误', () => {
worldManager.createWorld('duplicate-world');
expect(() => {
worldManager.createWorld('duplicate-world');
}).toThrow("World ID 'duplicate-world' 已存在");
});
test('超出最大World数量应该抛出错误', () => {
WorldManager['_instance'] = null;
const limitedManager = WorldManager.getInstance({ maxWorlds: 2 });
limitedManager.createWorld('world1');
limitedManager.createWorld('world2');
expect(() => {
limitedManager.createWorld('world3');
}).toThrow("已达到最大World数量限制: 2");
// 清理
limitedManager.removeWorld('world1');
limitedManager.removeWorld('world2');
});
test('获取World应该正确', () => {
const world = worldManager.createWorld('get-world');
const retrievedWorld = worldManager.getWorld('get-world');
expect(retrievedWorld).toBe(world);
});
test('获取不存在的World应该返回null', () => {
const world = worldManager.getWorld('non-existent');
expect(world).toBeNull();
});
test('检查World存在性应该正确', () => {
expect(worldManager.getWorld('non-existent')).toBeNull();
worldManager.createWorld('exists');
expect(worldManager.getWorld('exists')).toBeDefined();
});
test('销毁World应该正确清理', () => {
const world = worldManager.createWorld('destroy-world');
world.start();
const destroyed = worldManager.removeWorld('destroy-world');
expect(destroyed).toBe(true);
expect(worldManager.getWorld('destroy-world')).toBeNull();
});
test('销毁不存在的World应该返回false', () => {
const destroyed = worldManager.removeWorld('non-existent');
expect(destroyed).toBe(false);
});
test('获取所有World ID应该正确', () => {
worldManager.createWorld('world1');
worldManager.createWorld('world2');
worldManager.createWorld('world3');
const worldIds = worldManager.getWorldIds();
expect(worldIds).toHaveLength(3);
expect(worldIds).toContain('world1');
expect(worldIds).toContain('world2');
expect(worldIds).toContain('world3');
});
});
describe('活跃World管理', () => {
test('启动World应该加入活跃列表', () => {
const world = worldManager.createWorld('active-world');
worldManager.setWorldActive('active-world', true);
const activeWorlds = worldManager.getActiveWorlds();
expect(activeWorlds).toHaveLength(1);
expect(activeWorlds[0]).toBe(world);
});
test('停止World应该从活跃列表移除', () => {
const world = worldManager.createWorld('inactive-world');
worldManager.setWorldActive('inactive-world', true);
worldManager.setWorldActive('inactive-world', false);
const activeWorlds = worldManager.getActiveWorlds();
expect(activeWorlds).toHaveLength(0);
});
test('销毁激活的World应该从活跃列表移除', () => {
const world = worldManager.createWorld('destroy-active');
worldManager.setWorldActive('destroy-active', true);
worldManager.removeWorld('destroy-active');
const activeWorlds = worldManager.getActiveWorlds();
expect(activeWorlds).toHaveLength(0);
});
test('多个World的激活状态应该独立管理', () => {
const world1 = worldManager.createWorld('world1');
const world2 = worldManager.createWorld('world2');
const world3 = worldManager.createWorld('world3');
worldManager.setWorldActive('world1', true);
worldManager.setWorldActive('world3', true);
// world2 保持未启动
const activeWorlds = worldManager.getActiveWorlds();
expect(activeWorlds).toHaveLength(2);
expect(activeWorlds).toContain(world1);
expect(activeWorlds).toContain(world3);
expect(activeWorlds).not.toContain(world2);
});
});
describe('统计和监控', () => {
test('获取WorldManager状态应该正确', () => {
worldManager.createWorld('status-world1');
const world2 = worldManager.createWorld('status-world2');
worldManager.setWorldActive('status-world2', true);
const status = worldManager.getStats();
expect(status.totalWorlds).toBe(2);
expect(status.activeWorlds).toBe(1);
expect(status.config.maxWorlds).toBeGreaterThan(0);
expect(status.memoryUsage).toBeGreaterThanOrEqual(0);
expect(status.isRunning).toBeDefined();
});
test('获取所有World统计应该包含详细信息', () => {
const world1 = worldManager.createWorld('stats-world1');
const world2 = worldManager.createWorld('stats-world2');
// 为world1添加一些内容
const scene1 = world1.createScene('scene1');
scene1.createEntity('entity1');
worldManager.setWorldActive('stats-world1', true);
// world2保持空
const allStats = worldManager.getDetailedStatus().worlds;
expect(allStats).toHaveLength(2);
const world1Stats = allStats.find(stat => stat.id === 'stats-world1');
const world2Stats = allStats.find(stat => stat.id === 'stats-world2');
expect(world1Stats).toBeDefined();
expect(world2Stats).toBeDefined();
expect(world1Stats?.isActive).toBe(true);
expect(world2Stats?.isActive).toBe(false);
});
test('空WorldManager的统计应该正确', () => {
const status = worldManager.getStats();
const allStats = worldManager.getDetailedStatus().worlds;
expect(status.totalWorlds).toBe(0);
expect(status.activeWorlds).toBe(0);
expect(allStats).toHaveLength(0);
});
});
describe('清理功能', () => {
test('清理空闲World应该移除符合条件的World', () => {
// 创建一个空的World
const emptyWorld = worldManager.createWorld('empty-world');
// 创建一个有内容的World
const fullWorld = worldManager.createWorld('full-world');
const scene = fullWorld.createScene('scene');
scene.createEntity('entity');
fullWorld.start();
// 执行清理
const cleanedCount = worldManager.cleanup();
// 由于清理逻辑可能基于时间或其他条件,这里主要测试不会出错
expect(cleanedCount).toBeGreaterThanOrEqual(0);
expect(() => worldManager.cleanup()).not.toThrow();
});
});
describe('World更新协调', () => {
test('更新所有活跃World应该正确', () => {
const world1 = worldManager.createWorld('update-world1');
const world2 = worldManager.createWorld('update-world2');
const world3 = worldManager.createWorld('update-world3');
// 添加一些内容到World中
const scene1 = world1.createScene('scene1');
const scene2 = world2.createScene('scene2');
scene1.createEntity('entity1');
scene2.createEntity('entity2');
// 启动部分World
worldManager.setWorldActive('update-world1', true);
worldManager.setWorldActive('update-world2', true);
// world3保持未启动
// 手动调用更新通常由Core.update()调用)
const activeWorlds = worldManager.getActiveWorlds();
expect(() => {
activeWorlds.forEach(world => {
world.updateGlobalSystems();
world.updateScenes();
});
}).not.toThrow();
expect(activeWorlds).toHaveLength(2);
});
});
describe('边界情况和错误处理', () => {
test('World ID为空字符串应该抛出错误', () => {
expect(() => {
worldManager.createWorld('');
}).toThrow();
});
test('World ID为null或undefined应该抛出错误', () => {
expect(() => {
worldManager.createWorld(null as any);
}).toThrow();
expect(() => {
worldManager.createWorld(undefined as any);
}).toThrow();
});
test('极限情况下的大量World管理', () => {
const worldCount = 50;
const worldIds: string[] = [];
// 创建大量World
for (let i = 0; i < worldCount; i++) {
const worldId = `mass-world-${i}`;
worldIds.push(worldId);
expect(() => {
worldManager.createWorld(worldId);
}).not.toThrow();
}
expect(worldManager.getWorldIds()).toHaveLength(worldCount);
// 启动一半的World
for (let i = 0; i < worldCount / 2; i++) {
worldManager.setWorldActive(worldIds[i], true);
}
expect(worldManager.getActiveWorlds()).toHaveLength(worldCount / 2);
// 批量清理
worldIds.forEach(id => {
expect(() => {
worldManager.removeWorld(id);
}).not.toThrow();
});
expect(worldManager.getWorldIds()).toHaveLength(0);
});
test('销毁后获取World应该返回null', () => {
worldManager.createWorld('temp-world');
worldManager.removeWorld('temp-world');
expect(worldManager.getWorld('temp-world')).toBeNull();
});
});
describe('内存管理', () => {
test('销毁所有World后内存应该被释放', () => {
// 创建多个World并添加内容
for (let i = 0; i < 10; i++) {
const world = worldManager.createWorld(`memory-world-${i}`);
const scene = world.createScene('scene');
// 添加一些实体和系统
for (let j = 0; j < 5; j++) {
const entity = scene.createEntity(`entity-${j}`);
entity.addComponent(new TestComponent(j));
}
world.addGlobalSystem(new TestGlobalSystem());
worldManager.setWorldActive(`memory-world-${i}`, true);
}
const beforeCleanup = worldManager.getStats();
expect(beforeCleanup.totalWorlds).toBe(10);
expect(beforeCleanup.activeWorlds).toBe(10);
// 清理所有World
const worldIds = worldManager.getWorldIds();
worldIds.forEach(id => {
worldManager.removeWorld(id);
});
const afterCleanup = worldManager.getStats();
expect(afterCleanup.totalWorlds).toBe(0);
expect(afterCleanup.activeWorlds).toBe(0);
});
});
describe('配置验证', () => {
test('无效的maxWorlds配置应该使用默认值', () => {
WorldManager['_instance'] = null;
const invalidConfig: IWorldManagerConfig = {
maxWorlds: -1,
autoCleanup: true,
debug: true
};
expect(() => {
WorldManager.getInstance(invalidConfig);
}).not.toThrow();
});
test('配置更新应该影响后续操作', () => {
WorldManager['_instance'] = null;
const config: IWorldManagerConfig = {
maxWorlds: 3,
autoCleanup: true,
debug: true
};
const manager = WorldManager.getInstance(config);
// 创建到限制数量的World
manager.createWorld('world1');
manager.createWorld('world2');
manager.createWorld('world3');
// 第四个应该失败
expect(() => {
manager.createWorld('world4');
}).toThrow();
// 清理
manager.removeWorld('world1');
manager.removeWorld('world2');
manager.removeWorld('world3');
});
});
});