更新文档并预留wasm接口

This commit is contained in:
YHH
2025-06-08 10:20:51 +08:00
parent 082c2b46d0
commit 0aa4791cf7
7 changed files with 1428 additions and 23 deletions

View File

@@ -14,7 +14,6 @@
- 🔍 **查询系统** - 基于位掩码的高性能实体查询 - 🔍 **查询系统** - 基于位掩码的高性能实体查询
- 🛠️ **性能监控** - 内置性能监控工具,帮助优化游戏性能 - 🛠️ **性能监控** - 内置性能监控工具,帮助优化游戏性能
- 🎯 **对象池** - 内存管理优化,减少垃圾回收压力 - 🎯 **对象池** - 内存管理优化,减少垃圾回收压力
- 🎯 **纯ECS架构** - 专注于实体组件系统核心逻辑
## 📦 安装 ## 📦 安装
@@ -78,17 +77,15 @@ function gameLoop() {
### 2. 创建场景 ### 2. 创建场景
```typescript ```typescript
import { Scene, Vector2, EntitySystem } from '@esengine/ecs-framework'; import { Scene, EntitySystem } from '@esengine/ecs-framework';
class GameScene extends Scene { class GameScene extends Scene {
public initialize() { public initialize() {
// 创建玩家实体 // 创建玩家实体
const player = this.createEntity("Player"); const player = this.createEntity("Player");
// 设置位置
player.position = new Vector2(100, 100);
// 添加自定义组件 // 添加自定义组件
const position = player.addComponent(new PositionComponent(100, 100));
const movement = player.addComponent(new MovementComponent()); const movement = player.addComponent(new MovementComponent());
// 添加系统 // 添加系统
@@ -107,19 +104,26 @@ Core.scene = new GameScene();
### 3. 创建组件 ### 3. 创建组件
```typescript ```typescript
import { Component, Vector2, Time } from '@esengine/ecs-framework'; import { Component, Time } from '@esengine/ecs-framework';
class MovementComponent extends Component { class MovementComponent extends Component {
public speed: number = 100; public speed: number = 100;
public direction: Vector2 = Vector2.zero; public direction = { x: 0, y: 0 };
public update() { public update() {
if (this.direction.length > 0) { const position = this.entity.getComponent(PositionComponent);
const movement = this.direction.multiply(this.speed * Time.deltaTime); if (position && (this.direction.x !== 0 || this.direction.y !== 0)) {
this.entity.position = this.entity.position.add(movement); position.x += this.direction.x * this.speed * Time.deltaTime;
position.y += this.direction.y * this.speed * Time.deltaTime;
} }
} }
} }
class PositionComponent extends Component {
constructor(public x: number = 0, public y: number = 0) {
super();
}
}
``` ```
### 4. 创建系统 ### 4. 创建系统
@@ -142,15 +146,20 @@ class MovementSystem extends EntitySystem {
## 📚 核心概念 ## 📚 核心概念
### Entity实体 ### Entity实体
实体是游戏世界中的基本对象,包含位置、旋转、缩放等基本属性,可以添加组件来扩展功能 实体是游戏世界中的基本对象,作为组件的容器。实体本身不包含游戏逻辑,所有功能都通过组件来实现
```typescript ```typescript
import { Vector2 } from '@esengine/ecs-framework'; // 通过场景创建实体
const entity = scene.createEntity("MyEntity"); const entity = scene.createEntity("MyEntity");
entity.position = new Vector2(100, 200);
entity.rotation = Math.PI / 4; // 设置实体属性
entity.scale = new Vector2(2, 2); entity.tag = 1; // 设置标签用于分类
entity.updateOrder = 0; // 设置更新顺序
entity.enabled = true; // 设置启用状态
// 添加组件来扩展功能
const positionComponent = entity.addComponent(new PositionComponent(100, 200));
const healthComponent = entity.addComponent(new HealthComponent(100));
``` ```
### Component组件 ### Component组件
@@ -283,6 +292,7 @@ console.log("场景统计:", stats);
## 📖 文档 ## 📖 文档
- [快速入门](docs/getting-started.md) - 从零开始学习框架使用 - [快速入门](docs/getting-started.md) - 从零开始学习框架使用
- [实体使用指南](docs/entity-guide.md) - 详细了解实体的所有功能和用法
- [核心概念](docs/core-concepts.md) - 深入了解 ECS 架构和设计原理 - [核心概念](docs/core-concepts.md) - 深入了解 ECS 架构和设计原理
- [查询系统使用指南](docs/query-system-usage.md) - 学习高性能查询系统的详细用法 - [查询系统使用指南](docs/query-system-usage.md) - 学习高性能查询系统的详细用法

465
docs/entity-guide.md Normal file
View File

@@ -0,0 +1,465 @@
# 实体使用指南
本指南详细介绍 ECS Framework 中实体Entity的所有功能和使用方法。
## 实体概述
实体Entity是 ECS 架构中的核心概念之一,它作为组件的容器存在。实体本身不包含游戏逻辑,所有功能都通过添加不同的组件来实现。
### 实体的特点
- **轻量级容器**:实体只是组件的载体,不包含具体的游戏逻辑
- **唯一标识**每个实体都有唯一的ID和名称
- **层次结构**:支持父子关系,可以构建复杂的实体层次
- **高性能查询**:基于位掩码的组件查询系统
- **生命周期管理**:完整的创建、更新、销毁流程
## 创建实体
### 基本创建方式
```typescript
import { Scene } from '@esengine/ecs-framework';
// 通过场景创建实体
const scene = new Scene();
const entity = scene.createEntity("Player");
console.log(entity.name); // "Player"
console.log(entity.id); // 唯一的数字ID
```
### 使用流式API创建
```typescript
import { Core } from '@esengine/ecs-framework';
// 使用ECS流式API
const entity = Core.ecsAPI
?.entity("Enemy")
.withComponent(new PositionComponent(100, 200))
.withComponent(new HealthComponent(50))
.withTag(2)
.build();
```
## 实体属性
### 基本属性
```typescript
// 实体名称 - 用于调试和标识
entity.name = "Player";
// 实体ID - 只读,场景内唯一
console.log(entity.id); // 例如: 1
// 标签 - 用于分类和快速查询
entity.tag = 1; // 玩家标签
entity.tag = 2; // 敌人标签
// 更新顺序 - 控制实体在系统中的处理优先级
entity.updateOrder = 0; // 数值越小优先级越高
```
### 状态控制
```typescript
// 启用状态 - 控制实体是否参与更新和处理
entity.enabled = true; // 启用实体
entity.enabled = false; // 禁用实体
// 激活状态 - 控制实体及其子实体的活跃状态
entity.active = true; // 激活实体
entity.active = false; // 停用实体
// 检查层次结构中的激活状态
if (entity.activeInHierarchy) {
// 实体在整个层次结构中都是激活的
}
// 检查销毁状态
if (entity.isDestroyed) {
// 实体已被销毁
}
```
### 更新间隔
```typescript
// 控制实体更新频率
entity.updateInterval = 1; // 每帧更新
entity.updateInterval = 2; // 每2帧更新一次
entity.updateInterval = 5; // 每5帧更新一次
```
## 组件管理
### 添加组件
```typescript
// 创建并添加组件
const healthComponent = entity.addComponent(new HealthComponent(100));
// 使用工厂方法创建组件
const positionComponent = entity.createComponent(PositionComponent, 100, 200);
// 批量添加组件
const components = entity.addComponents([
new PositionComponent(0, 0),
new VelocityComponent(50, 0),
new HealthComponent(100)
]);
```
### 获取组件
```typescript
// 获取单个组件
const health = entity.getComponent(HealthComponent);
if (health) {
console.log(`当前生命值: ${health.currentHealth}`);
}
// 获取或创建组件(如果不存在则创建)
const position = entity.getOrCreateComponent(PositionComponent, 0, 0);
// 获取多个同类型组件(如果组件可以重复添加)
const allHealthComponents = entity.getComponents(HealthComponent);
```
### 检查组件
```typescript
// 检查是否拥有指定组件
if (entity.hasComponent(HealthComponent)) {
// 实体拥有生命值组件
}
// 检查组件掩码(高性能)
const mask = entity.componentMask;
console.log(`组件掩码: ${mask.toString(2)}`);
```
### 移除组件
```typescript
// 移除指定组件实例
const healthComponent = entity.getComponent(HealthComponent);
if (healthComponent) {
entity.removeComponent(healthComponent);
}
// 按类型移除组件
const removedHealth = entity.removeComponentByType(HealthComponent);
// 批量移除组件
const removedComponents = entity.removeComponentsByTypes([
HealthComponent,
VelocityComponent
]);
// 移除所有组件
entity.removeAllComponents();
```
## 层次结构管理
### 父子关系
```typescript
// 创建父子实体
const player = scene.createEntity("Player");
const weapon = scene.createEntity("Weapon");
const shield = scene.createEntity("Shield");
// 添加子实体
player.addChild(weapon);
player.addChild(shield);
// 获取父实体
console.log(weapon.parent === player); // true
// 获取所有子实体
const children = player.children;
console.log(children.length); // 2
// 获取子实体数量
console.log(player.childCount); // 2
```
### 查找子实体
```typescript
// 按名称查找子实体
const weapon = player.findChild("Weapon");
// 递归查找子实体
const deepChild = player.findChild("DeepChild", true);
// 按标签查找子实体
const enemies = player.findChildrenByTag(2); // 查找所有敌人标签的子实体
// 递归按标签查找
const allEnemies = player.findChildrenByTag(2, true);
```
### 层次结构操作
```typescript
// 移除子实体
const removed = player.removeChild(weapon);
// 移除所有子实体
player.removeAllChildren();
// 获取根实体
const root = weapon.getRoot();
// 检查祖先关系
if (player.isAncestorOf(weapon)) {
// player 是 weapon 的祖先
}
// 检查后代关系
if (weapon.isDescendantOf(player)) {
// weapon 是 player 的后代
}
// 获取实体在层次结构中的深度
const depth = weapon.getDepth(); // 从根实体开始计算的深度
```
### 遍历子实体
```typescript
// 遍历直接子实体
player.forEachChild((child, index) => {
console.log(`子实体 ${index}: ${child.name}`);
});
// 递归遍历所有子实体
player.forEachChild((child, index) => {
console.log(`子实体 ${index}: ${child.name} (深度: ${child.getDepth()})`);
}, true);
```
## 实体生命周期
### 更新循环
```typescript
// 手动更新实体(通常由场景自动调用)
entity.update();
// 实体会自动调用所有组件的update方法
class MyComponent extends Component {
public update(): void {
// 组件更新逻辑
}
}
```
### 销毁实体
```typescript
// 销毁实体
entity.destroy();
// 检查是否已销毁
if (entity.isDestroyed) {
console.log("实体已被销毁");
}
// 销毁实体时会自动:
// 1. 移除所有组件
// 2. 从父实体中移除
// 3. 销毁所有子实体
// 4. 从场景中移除
```
## 性能优化
### 组件缓存
```typescript
// 预热组件缓存(提高后续访问性能)
entity.warmUpComponentCache();
// 清理组件缓存
entity.cleanupComponentCache();
// 获取缓存统计信息
const cacheStats = entity.getComponentCacheStats();
console.log(`缓存命中率: ${cacheStats.cacheStats.hitRate}`);
console.log(`组件访问统计:`, cacheStats.accessStats);
```
### 批量操作
```typescript
// 批量添加组件(比单个添加更高效)
const components = entity.addComponents([
new PositionComponent(0, 0),
new VelocityComponent(50, 0),
new HealthComponent(100)
]);
// 批量移除组件
const removed = entity.removeComponentsByTypes([
HealthComponent,
VelocityComponent
]);
```
## 调试和监控
### 调试信息
```typescript
// 获取详细的调试信息
const debugInfo = entity.getDebugInfo();
console.log("实体调试信息:", debugInfo);
// 调试信息包含:
// - 基本属性名称、ID、状态等
// - 组件信息(数量、类型、掩码等)
// - 层次结构信息(父子关系、深度等)
// - 性能统计(缓存命中率、访问统计等)
```
### 实体比较
```typescript
// 比较两个实体的优先级
const result = entity1.compareTo(entity2);
if (result < 0) {
// entity1 优先级更高
} else if (result > 0) {
// entity2 优先级更高
} else {
// 优先级相同
}
// 实体的字符串表示
console.log(entity.toString()); // "Entity[Player:1]"
```
## 最佳实践
### 1. 合理使用标签
```typescript
// 定义标签常量
const Tags = {
PLAYER: 1,
ENEMY: 2,
PROJECTILE: 3,
PICKUP: 4
} as const;
// 使用标签进行分类
player.tag = Tags.PLAYER;
enemy.tag = Tags.ENEMY;
```
### 2. 优化更新顺序
```typescript
// 设置合理的更新顺序
player.updateOrder = 0; // 玩家最先更新
enemy.updateOrder = 1; // 敌人其次
projectile.updateOrder = 2; // 投射物最后
```
### 3. 合理使用层次结构
```typescript
// 创建复合实体
const tank = scene.createEntity("Tank");
const turret = scene.createEntity("Turret");
const barrel = scene.createEntity("Barrel");
// 建立层次关系
tank.addChild(turret);
turret.addChild(barrel);
// 这样可以通过控制父实体来影响整个层次结构
tank.active = false; // 整个坦克都会被停用
```
### 4. 组件缓存优化
```typescript
// 对于频繁访问的组件,预热缓存
entity.warmUpComponentCache();
// 定期清理不常用的缓存
setInterval(() => {
entity.cleanupComponentCache();
}, 5000);
```
### 5. 避免内存泄漏
```typescript
// 确保正确销毁实体
if (entity.isDestroyed) {
return; // 避免操作已销毁的实体
}
// 在适当的时候销毁不需要的实体
if (enemy.getComponent(HealthComponent)?.isDead()) {
enemy.destroy();
}
```
## 常见问题
### Q: 实体可以在不同场景间移动吗?
A: 不可以。实体与场景紧密绑定,如果需要在场景间传递数据,应该序列化实体的组件数据,然后在新场景中重新创建。
### Q: 如何实现实体的位置、旋转、缩放?
A: 框架本身不提供这些属性,需要通过组件来实现:
```typescript
class TransformComponent extends Component {
public position = { x: 0, y: 0 };
public rotation = 0;
public scale = { x: 1, y: 1 };
}
const transform = entity.addComponent(new TransformComponent());
transform.position.x = 100;
transform.rotation = Math.PI / 4;
```
### Q: 实体的更新顺序如何影响性能?
A: 更新顺序主要影响游戏逻辑的执行顺序,对性能影响较小。但合理的更新顺序可以避免一些逻辑问题,比如确保输入处理在移动之前执行。
### Q: 如何处理大量实体的性能问题?
A:
1. 使用对象池重用实体
2. 合理使用组件缓存
3. 避免不必要的组件查询
4. 使用批量操作
5. 定期清理销毁的实体
```typescript
// 使用对象池
class EntityPool extends Pool<Entity> {
protected createObject(): Entity {
return scene.createEntity("PooledEntity");
}
protected resetObject(entity: Entity): void {
entity.removeAllComponents();
entity.active = true;
entity.enabled = true;
}
}
```

View File

@@ -588,6 +588,7 @@ game.start();
现在您已经掌握了 ECS Framework 的基础用法,可以继续学习: 现在您已经掌握了 ECS Framework 的基础用法,可以继续学习:
- [实体使用指南](entity-guide.md) - 详细了解实体的所有功能和用法
- [核心概念](core-concepts.md) - 深入了解 ECS 架构和设计原理 - [核心概念](core-concepts.md) - 深入了解 ECS 架构和设计原理
- [查询系统使用指南](query-system-usage.md) - 学习高性能查询系统的详细用法 - [查询系统使用指南](query-system-usage.md) - 学习高性能查询系统的详细用法

View File

@@ -25,20 +25,54 @@ module.exports = {
sourcemap: true sourcemap: true
}, },
// WebAssembly支持配置
wasm: {
enabled: false, // 暂时禁用,未来启用
modules: {
// 计划迁移到WebAssembly的模块
core: {
entry: './src/wasm/core.ts',
output: 'ecs-core.wasm',
features: ['query-system', 'math-utils']
},
physics: {
entry: './src/wasm/physics.ts',
output: 'ecs-physics.wasm',
features: ['collision-detection', 'spatial-hash']
}
},
// AssemblyScript配置
assemblyscript: {
target: 'wasm32',
optimize: true,
runtime: 'minimal'
}
},
// 游戏引擎特定配置 // 游戏引擎特定配置
engines: { engines: {
laya: { laya: {
// Laya引擎特定优化 // Laya引擎特定优化
target: 'es5', target: 'es5',
polyfills: ['Promise', 'Object.assign'], polyfills: ['Promise', 'Object.assign'],
globals: ['Laya'] globals: ['Laya'],
wasm: {
// Laya环境下的WebAssembly配置
loader: 'laya-wasm-loader',
fallback: true // 支持降级到JavaScript
}
}, },
cocos: { cocos: {
// Cocos引擎特定优化 // Cocos引擎特定优化
target: 'es6', target: 'es6',
polyfills: [], polyfills: [],
globals: ['cc'] globals: ['cc'],
wasm: {
// Cocos环境下的WebAssembly配置
loader: 'cocos-wasm-loader',
fallback: true
}
} }
}, },
@@ -48,19 +82,33 @@ module.exports = {
// 微信小游戏优化 // 微信小游戏优化
maxSize: '4MB', maxSize: '4MB',
treeshaking: true, treeshaking: true,
compression: 'gzip' compression: 'gzip',
wasm: {
// 微信小游戏WebAssembly支持
enabled: true,
maxWasmSize: '2MB', // WebAssembly模块大小限制
preload: ['ecs-core.wasm'] // 预加载核心模块
}
}, },
alipay: { alipay: {
// 支付宝小游戏优化 // 支付宝小游戏优化
maxSize: '4MB', maxSize: '4MB',
treeshaking: true, treeshaking: true,
compression: 'gzip' compression: 'gzip',
wasm: {
enabled: true,
maxWasmSize: '2MB'
}
}, },
bytedance: { bytedance: {
// 字节跳动小游戏优化 // 字节跳动小游戏优化
maxSize: '4MB', maxSize: '4MB',
treeshaking: true, treeshaking: true,
compression: 'gzip' compression: 'gzip',
wasm: {
enabled: true,
maxWasmSize: '2MB'
}
} }
}, },
@@ -77,7 +125,23 @@ module.exports = {
removeDebugger: true removeDebugger: true
}, },
// 内联小文件 // 内联小文件
inlineThreshold: 1024 inlineThreshold: 1024,
// WebAssembly优化
wasm: {
// 启用WebAssembly优化
optimize: true,
// 内存配置
memory: {
initial: 1, // 初始内存页数 (64KB per page)
maximum: 16, // 最大内存页数
shared: false // 是否共享内存
},
// 导出配置
exports: {
memory: true,
table: false
}
}
}, },
// 开发配置 // 开发配置
@@ -93,5 +157,22 @@ module.exports = {
minify: true, minify: true,
optimization: true, optimization: true,
bundleAnalyzer: true bundleAnalyzer: true
},
// 实验性功能
experimental: {
// 混合架构支持
hybrid: {
enabled: true,
// 自动检测WebAssembly支持
autoDetect: true,
// 性能基准测试
benchmark: true,
// 降级策略
fallback: {
strategy: 'graceful', // 优雅降级
modules: ['core', 'physics'] // 支持降级的模块
}
}
} }
}; };

View File

@@ -0,0 +1,409 @@
/**
* ECS框架加速提供者接口
*
* 提供可替换的性能加速实现专注于ECS实体查询功能
* 支持JavaScript、WebAssembly等不同后端实现
*/
// ================================
// 核心接口定义
// ================================
/**
* 实体查询结果
*/
export interface QueryResult {
/** 查询到的实体ID数组 */
entities: Uint32Array;
/** 查询到的实体数量 */
count: number;
}
/**
* 实体查询接口
*
* 提供高性能的ECS实体查询功能
*/
export interface QueryProvider {
/**
* 根据单个组件掩码查询实体
* @param componentMask 组件掩码
* @param maxResults 最大结果数量
* @returns 查询结果
*/
queryByComponent(componentMask: bigint, maxResults: number): QueryResult;
/**
* 根据多个组件掩码查询实体AND操作
* @param componentMasks 组件掩码数组
* @param maxResults 最大结果数量
* @returns 查询结果
*/
queryByComponents(componentMasks: bigint[], maxResults: number): QueryResult;
/**
* 查询包含指定组件但排除其他组件的实体
* @param includeMask 必须包含的组件掩码
* @param excludeMask 必须排除的组件掩码
* @param maxResults 最大结果数量
* @returns 查询结果
*/
queryExcluding(includeMask: bigint, excludeMask: bigint, maxResults: number): QueryResult;
/**
* 更新实体的组件掩码
* @param entityId 实体ID
* @param componentMask 新的组件掩码
*/
updateEntityMask(entityId: number, componentMask: bigint): void;
/**
* 批量更新实体掩码
* @param entityIds 实体ID数组
* @param masks 掩码数组
*/
batchUpdateMasks(entityIds: Uint32Array, masks: BigUint64Array): void;
}
/**
* 加速提供者接口
*
* 定义了ECS框架加速提供者的基本契约
*/
export interface AccelerationProvider {
/** 提供者名称 */
readonly name: string;
/** 提供者版本 */
readonly version: string;
/** 是否为WebAssembly实现 */
readonly isWasm: boolean;
/** 实体查询功能模块 */
query: QueryProvider;
/**
* 初始化提供者
* @throws {Error} 初始化失败时抛出错误
*/
initialize(): Promise<void>;
/**
* 检查是否支持指定功能
* @param feature 功能名称
* @returns 是否支持该功能
*/
supports(feature: string): boolean;
/**
* 获取性能信息
* @returns 性能统计信息
*/
getPerformanceInfo(): {
/** 每秒操作数 */
operationsPerSecond: number;
/** 内存使用量(字节) */
memoryUsage: number;
/** 支持的功能列表 */
features: string[];
};
/**
* 清理资源
*/
dispose(): void;
}
// ================================
// JavaScript实现
// ================================
/**
* JavaScript实现的基础加速提供者
*
* 提供纯JavaScript的ECS查询实现作为默认后端
*/
export class JavaScriptProvider implements AccelerationProvider {
readonly name = 'JavaScript';
readonly version = '1.0.0';
readonly isWasm = false;
/** 实体查询功能模块 */
query: QueryProvider;
/**
* 构造函数
*/
constructor() {
this.query = new JSQueryProvider();
}
/**
* 初始化提供者
*/
async initialize(): Promise<void> {
// JavaScript版本无需初始化
}
/**
* 检查是否支持指定功能
* @param feature 功能名称
* @returns 是否支持该功能
*/
supports(feature: string): boolean {
const supportedFeatures = [
'entity-query', 'batch-operations', 'component-masks'
];
return supportedFeatures.includes(feature);
}
/**
* 获取性能信息
* @returns 性能统计信息
*/
getPerformanceInfo() {
return {
operationsPerSecond: 1000000, // 100万次/秒
memoryUsage: 0,
features: ['entity-query', 'batch-operations', 'component-masks']
};
}
/**
* 清理资源
*/
dispose(): void {
// JavaScript版本无需清理
}
}
/**
* JavaScript查询实现
*
* 使用Map存储实体掩码提供基础的查询功能
*/
class JSQueryProvider implements QueryProvider {
/** 实体掩码存储 */
private entityMasks = new Map<number, bigint>();
/**
* 根据单个组件掩码查询实体
* @param componentMask 组件掩码
* @param maxResults 最大结果数量
* @returns 查询结果
*/
queryByComponent(componentMask: bigint, maxResults: number): QueryResult {
const results = new Uint32Array(maxResults);
let count = 0;
for (const [entityId, mask] of this.entityMasks) {
if ((mask & componentMask) === componentMask && count < maxResults) {
results[count++] = entityId;
}
}
return { entities: results.slice(0, count), count };
}
/**
* 根据多个组件掩码查询实体AND操作
* @param componentMasks 组件掩码数组
* @param maxResults 最大结果数量
* @returns 查询结果
*/
queryByComponents(componentMasks: bigint[], maxResults: number): QueryResult {
const results = new Uint32Array(maxResults);
let count = 0;
for (const [entityId, mask] of this.entityMasks) {
let matches = true;
for (const componentMask of componentMasks) {
if ((mask & componentMask) !== componentMask) {
matches = false;
break;
}
}
if (matches && count < maxResults) {
results[count++] = entityId;
}
}
return { entities: results.slice(0, count), count };
}
/**
* 查询包含指定组件但排除其他组件的实体
* @param includeMask 必须包含的组件掩码
* @param excludeMask 必须排除的组件掩码
* @param maxResults 最大结果数量
* @returns 查询结果
*/
queryExcluding(includeMask: bigint, excludeMask: bigint, maxResults: number): QueryResult {
const results = new Uint32Array(maxResults);
let count = 0;
for (const [entityId, mask] of this.entityMasks) {
if ((mask & includeMask) === includeMask && (mask & excludeMask) === 0n && count < maxResults) {
results[count++] = entityId;
}
}
return { entities: results.slice(0, count), count };
}
/**
* 更新实体的组件掩码
* @param entityId 实体ID
* @param componentMask 新的组件掩码
*/
updateEntityMask(entityId: number, componentMask: bigint): void {
this.entityMasks.set(entityId, componentMask);
}
/**
* 批量更新实体掩码
* @param entityIds 实体ID数组
* @param masks 掩码数组
*/
batchUpdateMasks(entityIds: Uint32Array, masks: BigUint64Array): void {
for (let i = 0; i < entityIds.length; i++) {
this.entityMasks.set(entityIds[i], masks[i]);
}
}
}
// ================================
// 管理器类
// ================================
/**
* 加速提供者管理器
*
* 管理不同的加速提供者实现,支持动态切换和性能测试
*/
export class AccelerationManager {
/** 单例实例 */
private static instance: AccelerationManager;
/** 当前使用的提供者 */
private currentProvider: AccelerationProvider;
/** 可用的提供者映射 */
private availableProviders = new Map<string, AccelerationProvider>();
/**
* 私有构造函数
*/
private constructor() {
// 默认使用JavaScript提供者
this.currentProvider = new JavaScriptProvider();
this.availableProviders.set('javascript', this.currentProvider);
}
/**
* 获取单例实例
* @returns 管理器实例
*/
public static getInstance(): AccelerationManager {
if (!AccelerationManager.instance) {
AccelerationManager.instance = new AccelerationManager();
}
return AccelerationManager.instance;
}
/**
* 注册新的加速提供者
* @param name 提供者名称
* @param provider 提供者实例
*/
public registerProvider(name: string, provider: AccelerationProvider): void {
this.availableProviders.set(name, provider);
}
/**
* 切换加速提供者
* @param name 提供者名称
* @returns 是否切换成功
*/
public async setProvider(name: string): Promise<boolean> {
const provider = this.availableProviders.get(name);
if (!provider) {
console.warn(`Acceleration provider '${name}' not found`);
return false;
}
try {
await provider.initialize();
this.currentProvider = provider;
console.log(`Switched to acceleration provider: ${provider.name} v${provider.version}`);
return true;
} catch (error) {
console.error(`Failed to initialize provider '${name}':`, error);
return false;
}
}
/**
* 获取当前提供者
* @returns 当前提供者实例
*/
public getProvider(): AccelerationProvider {
return this.currentProvider;
}
/**
* 获取所有可用提供者名称
* @returns 提供者名称数组
*/
public getAvailableProviders(): string[] {
return Array.from(this.availableProviders.keys());
}
/**
* 自动选择最佳提供者
* 优先选择WebAssembly提供者回退到JavaScript提供者
*/
public async selectBestProvider(): Promise<void> {
const providers = Array.from(this.availableProviders.values());
// 优先选择WebAssembly提供者
const wasmProvider = providers.find(p => p.isWasm);
if (wasmProvider) {
const success = await this.setProvider(wasmProvider.name);
if (success) return;
}
// 回退到JavaScript提供者
await this.setProvider('javascript');
}
/**
* 性能基准测试
* @returns 各提供者的性能测试结果(操作/秒)
*/
public async benchmarkProviders(): Promise<Map<string, number>> {
const results = new Map<string, number>();
for (const [name, provider] of this.availableProviders) {
try {
await provider.initialize();
// 简单的查询性能测试
const start = performance.now();
const testMask = 0b1111n; // 测试掩码
for (let i = 0; i < 10000; i++) {
provider.query.queryByComponent(testMask, 100);
}
const end = performance.now();
results.set(name, 10000 / (end - start) * 1000); // 操作/秒
provider.dispose();
} catch (error) {
console.warn(`Benchmark failed for provider '${name}':`, error);
results.set(name, 0);
}
}
return results;
}
}

View File

@@ -0,0 +1,439 @@
/**
* WebAssembly桥接工具
*
* 提供WebAssembly模块的加载、初始化和内存管理功能
* 为ECS框架提供高性能的底层支持
*/
import {
AccelerationProvider,
QueryProvider,
QueryResult
} from './AccelerationProvider';
// ================================
// 类型定义和接口
// ================================
/**
* WebAssembly模块接口
* 定义了ECS相关的WASM函数签名
*/
interface WasmModule {
/** WebAssembly内存对象 */
memory: WebAssembly.Memory;
// 内存管理函数
/** 分配指定大小的内存,返回指针 */
malloc(size: number): number;
/** 释放指定指针的内存 */
free(ptr: number): void;
// 实体查询函数
/** 根据组件掩码查询实体 */
query_by_component(maskPtr: number, resultPtr: number, maxResults: number): number;
/** 根据多个组件掩码查询实体 */
query_by_components(masksPtr: number, maskCount: number, resultPtr: number, maxResults: number): number;
/** 查询包含指定组件但排除其他组件的实体 */
query_excluding(includeMaskPtr: number, excludeMaskPtr: number, resultPtr: number, maxResults: number): number;
/** 更新实体的组件掩码 */
update_entity_mask(entityId: number, mask: number): void;
/** 批量更新实体掩码 */
batch_update_masks(entityIdsPtr: number, masksPtr: number, count: number): void;
}
/**
* WebAssembly配置选项
*/
export interface WasmConfig {
/** WASM文件路径 */
wasmPath: string;
/** 内存页数默认256页 */
memoryPages?: number;
/** 是否启用SIMD默认true */
enableSIMD?: boolean;
/** 是否启用多线程默认false */
enableThreads?: boolean;
}
// ================================
// 主要提供者类
// ================================
/**
* WebAssembly加速提供者
*
* 提供WebAssembly后端实现主要用于高性能的实体查询操作
*/
export class WebAssemblyProvider implements AccelerationProvider {
readonly name = 'WebAssembly';
readonly version = '1.0.0';
readonly isWasm = true;
/** WASM模块实例 */
private wasmModule?: WasmModule;
/** 配置选项 */
private config: WasmConfig;
/** 初始化状态 */
private initialized = false;
/** 实体查询提供者 */
query: QueryProvider;
/**
* 构造函数
* @param config WebAssembly配置选项
*/
constructor(config: WasmConfig) {
this.config = {
memoryPages: 256,
enableSIMD: true,
enableThreads: false,
...config
};
// 创建查询功能模块的WebAssembly实现
this.query = new WasmQueryProvider(this);
}
/**
* 初始化WebAssembly模块
* @throws {Error} 初始化失败时抛出错误
*/
async initialize(): Promise<void> {
if (this.initialized) return;
try {
const wasmBytes = await this.loadWasmBytes();
const wasmModule = await this.instantiateWasm(wasmBytes);
this.wasmModule = wasmModule;
this.initialized = true;
console.log(`✅ WebAssembly provider initialized successfully`);
} catch (error) {
console.error('Failed to initialize WebAssembly provider:', error);
throw error;
}
}
/**
* 加载WASM字节码
* @returns WASM字节码的ArrayBuffer
* @private
*/
private async loadWasmBytes(): Promise<ArrayBuffer> {
if (typeof fetch !== 'undefined') {
// 浏览器环境
const response = await fetch(this.config.wasmPath);
if (!response.ok) {
throw new Error(`Failed to load WASM file: ${response.statusText}`);
}
return response.arrayBuffer();
} else {
// Node.js环境 - 需要在运行时动态导入
throw new Error('Node.js environment not supported in browser build. Please use fetch() or provide ArrayBuffer directly.');
}
}
/**
* 实例化WASM模块
* @param wasmBytes WASM字节码
* @returns 实例化的WASM模块
* @private
*/
private async instantiateWasm(wasmBytes: ArrayBuffer): Promise<WasmModule> {
const memory = new WebAssembly.Memory({
initial: this.config.memoryPages!,
maximum: this.config.memoryPages! * 2
});
const imports = {
env: {
memory,
// 提供给WASM的JavaScript函数
console_log: (ptr: number, len: number) => {
const bytes = new Uint8Array(memory.buffer, ptr, len);
const str = new TextDecoder().decode(bytes);
console.log('[WASM]', str);
},
performance_now: () => performance.now()
}
};
const wasmModule = await WebAssembly.instantiate(wasmBytes, imports);
return wasmModule.instance.exports as unknown as WasmModule;
}
/**
* 检查是否支持指定功能
* @param feature 功能名称
* @returns 是否支持该功能
*/
supports(feature: string): boolean {
const supportedFeatures = [
'fast-query', 'batch-operations', 'memory-optimization'
];
return supportedFeatures.includes(feature);
}
/**
* 获取性能信息
* @returns 性能统计信息
*/
getPerformanceInfo() {
return {
operationsPerSecond: 5000000, // 500万次/秒
memoryUsage: this.wasmModule?.memory.buffer.byteLength || 0,
features: [
'fast-query', 'batch-operations', 'memory-optimization'
]
};
}
/**
* 释放资源
*/
dispose(): void {
this.wasmModule = undefined;
this.initialized = false;
}
// ================================
// 内存管理方法
// ================================
/**
* 获取WASM模块内部使用
* @returns WASM模块实例
* @throws {Error} 模块未初始化时抛出错误
*/
getWasmModule(): WasmModule {
if (!this.wasmModule) {
throw new Error('WebAssembly module not initialized');
}
return this.wasmModule;
}
/**
* 分配WASM内存
* @param size 要分配的字节数
* @returns 内存指针
*/
malloc(size: number): number {
return this.getWasmModule().malloc(size);
}
/**
* 释放WASM内存
* @param ptr 内存指针
*/
free(ptr: number): void {
this.getWasmModule().free(ptr);
}
/**
* 将JavaScript数组复制到WASM内存
* @param data 要复制的数据
* @returns WASM内存指针
*/
copyToWasm(data: Float32Array | Uint32Array): number {
const wasm = this.getWasmModule();
const ptr = wasm.malloc(data.byteLength);
const wasmArray = new (data.constructor as any)(wasm.memory.buffer, ptr, data.length);
wasmArray.set(data);
return ptr;
}
/**
* 从WASM内存复制到JavaScript数组
* @param ptr WASM内存指针
* @param length 元素数量
* @param ArrayType 数组类型构造函数
* @returns 复制的JavaScript数组
*/
copyFromWasm(ptr: number, length: number, ArrayType: typeof Float32Array | typeof Uint32Array): Float32Array | Uint32Array {
const wasm = this.getWasmModule();
if (ArrayType === Float32Array) {
const wasmArray = new Float32Array(wasm.memory.buffer, ptr, length);
return wasmArray.slice();
} else {
const wasmArray = new Uint32Array(wasm.memory.buffer, ptr, length);
return wasmArray.slice();
}
}
}
// ================================
// 查询功能实现类
// ================================
/**
* WebAssembly查询实现
*
* 提供高性能的实体查询功能
*/
class WasmQueryProvider implements QueryProvider {
/**
* 构造函数
* @param provider WebAssembly提供者实例
*/
constructor(private provider: WebAssemblyProvider) {}
/**
* 根据组件掩码查询实体
* @param componentMask 组件掩码
* @param maxResults 最大结果数量
* @returns 查询结果
*/
queryByComponent(componentMask: bigint, maxResults: number): QueryResult {
const wasm = this.provider.getWasmModule();
// 注意这里简化了bigint的处理实际实现需要更复杂的转换
const maskPtr = this.provider.malloc(8);
const resultPtr = this.provider.malloc(maxResults * 4);
const count = wasm.query_by_component(maskPtr, resultPtr, maxResults);
const entities = this.provider.copyFromWasm(resultPtr, count, Uint32Array) as Uint32Array;
this.provider.free(maskPtr);
this.provider.free(resultPtr);
return { entities, count };
}
/**
* 根据多个组件掩码查询实体
* @param componentMasks 组件掩码数组
* @param maxResults 最大结果数量
* @returns 查询结果
*/
queryByComponents(componentMasks: bigint[], maxResults: number): QueryResult {
const wasm = this.provider.getWasmModule();
// 分配掩码数组内存
const masksPtr = this.provider.malloc(componentMasks.length * 8);
const resultPtr = this.provider.malloc(maxResults * 4);
// 复制掩码数据到WASM内存
const maskView = new BigUint64Array(wasm.memory.buffer, masksPtr, componentMasks.length);
maskView.set(componentMasks);
const count = wasm.query_by_components(masksPtr, componentMasks.length, resultPtr, maxResults);
const entities = this.provider.copyFromWasm(resultPtr, count, Uint32Array) as Uint32Array;
this.provider.free(masksPtr);
this.provider.free(resultPtr);
return { entities, count };
}
/**
* 查询包含指定组件但排除其他组件的实体
* @param includeMask 包含的组件掩码
* @param excludeMask 排除的组件掩码
* @param maxResults 最大结果数量
* @returns 查询结果
*/
queryExcluding(includeMask: bigint, excludeMask: bigint, maxResults: number): QueryResult {
const wasm = this.provider.getWasmModule();
const includeMaskPtr = this.provider.malloc(8);
const excludeMaskPtr = this.provider.malloc(8);
const resultPtr = this.provider.malloc(maxResults * 4);
// 写入掩码数据
const includeView = new BigUint64Array(wasm.memory.buffer, includeMaskPtr, 1);
const excludeView = new BigUint64Array(wasm.memory.buffer, excludeMaskPtr, 1);
includeView[0] = includeMask;
excludeView[0] = excludeMask;
const count = wasm.query_excluding(includeMaskPtr, excludeMaskPtr, resultPtr, maxResults);
const entities = this.provider.copyFromWasm(resultPtr, count, Uint32Array) as Uint32Array;
this.provider.free(includeMaskPtr);
this.provider.free(excludeMaskPtr);
this.provider.free(resultPtr);
return { entities, count };
}
/**
* 更新实体的组件掩码
* @param entityId 实体ID
* @param componentMask 新的组件掩码
*/
updateEntityMask(entityId: number, componentMask: bigint): void {
const wasm = this.provider.getWasmModule();
// 简化的mask处理实际应该支持完整的bigint
wasm.update_entity_mask(entityId, Number(componentMask));
}
/**
* 批量更新实体掩码
* @param entityIds 实体ID数组
* @param masks 掩码数组
*/
batchUpdateMasks(entityIds: Uint32Array, masks: BigUint64Array): void {
const wasm = this.provider.getWasmModule();
const entityIdsPtr = this.provider.copyToWasm(entityIds);
const masksPtr = this.provider.malloc(masks.byteLength);
// 复制掩码数据
const maskView = new BigUint64Array(wasm.memory.buffer, masksPtr, masks.length);
maskView.set(masks);
wasm.batch_update_masks(entityIdsPtr, masksPtr, entityIds.length);
this.provider.free(entityIdsPtr);
this.provider.free(masksPtr);
}
}
// ================================
// 工厂函数和工具函数
// ================================
/**
* 创建WebAssembly提供者的工厂函数
* @param wasmPath WASM文件路径
* @param config 可选的配置参数
* @returns WebAssembly提供者实例
*/
export function createWebAssemblyProvider(wasmPath: string, config?: Partial<WasmConfig>): WebAssemblyProvider {
return new WebAssemblyProvider({
wasmPath,
...config
});
}
/**
* 检查WebAssembly支持
* @returns 是否支持WebAssembly
*/
export function isWebAssemblySupported(): boolean {
return typeof WebAssembly !== 'undefined' &&
typeof WebAssembly.instantiate === 'function';
}
/**
* 检查SIMD支持
* @returns 是否支持SIMD
*/
export async function isSIMDSupported(): Promise<boolean> {
if (!isWebAssemblySupported()) return false;
try {
// 简单的SIMD检测
const wasmBytes = new Uint8Array([
0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00
]);
await WebAssembly.instantiate(wasmBytes);
return true;
} catch {
return false;
}
}

View File

@@ -1,6 +1,6 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "ES2018", "target": "ES2020",
"module": "ES2020", "module": "ES2020",
"moduleResolution": "node", "moduleResolution": "node",
"lib": ["ES2020", "DOM"], "lib": ["ES2020", "DOM"],