/** * WASM 物理引擎实现 * 提供与 pinball-physics WASM 模块的接口 */ import { wasmLoader } from '../../../Utils/WasmLoader'; import { BodyId, PhysicsBodyData, PhysicsSettings, Vector2, WorldId } from '../Core/GameData'; import { IPhysicsEngine } from '../Core/IPhysicsEngine'; import { WasmExports, WasmModuleState } from './PhysicsTypes'; export class WasmPhysicsEngine implements IPhysicsEngine { private wasmModule: WebAssembly.Module | null = null; private wasmInstance: WebAssembly.Instance | null = null; private wasmExports: WasmExports | null = null; private state: WasmModuleState = WasmModuleState.UNLOADED; private worlds: Map = new Map(); private bodies: Map> = new Map(); /** * 初始化 WASM 物理引擎 * @param settings 物理设置 * @param wasmFactory WASM工厂函数(可选,推荐使用) */ async initialize(settings: PhysicsSettings, wasmFactory?: any): Promise { if (this.state === WasmModuleState.LOADED) { return; } this.state = WasmModuleState.LOADING; try { if (wasmFactory) { // 使用新的 WasmLoader(推荐方式) await this.initializeWithWasmLoader(wasmFactory); } else { // 回退到旧的加载方式(保持向后兼容) console.warn('使用旧的 WASM 加载方式,推荐提供 wasmFactory 参数使用 WasmLoader'); await this.initializeLegacy(); } this.state = WasmModuleState.LOADED; console.log('WASM Physics Engine initialized successfully'); } catch (error) { this.state = WasmModuleState.ERROR; console.error('Failed to initialize WASM Physics Engine:', error); throw error; } } /** * 创建 WASM 导入对象 */ private createImportObject(): WebAssembly.Imports { return { env: { // 内存管理 memory: new WebAssembly.Memory({ initial: 10, maximum: 100 }), // 日志函数 console_log: (ptr: number, len: number) => { // 可以实现 WASM 的日志输出 }, // 错误处理 abort: (msg: number, file: number, line: number, col: number) => { console.error('WASM abort:', { msg, file, line, col }); } } }; } /** * 使用 WasmLoader 初始化(推荐方式) */ private async initializeWithWasmLoader(wasmFactory: any): Promise { // 初始化 WASM 加载器 wasmLoader.initialize(); // 检查平台支持 if (!wasmLoader.isWasmSupported()) { throw new Error('当前平台不支持 WASM,需要提供 ASM 回退选项'); } // 加载 WASM 模块 // 注意:在实际使用时需要提供正确的 editorUuid const instance = await wasmLoader.loadSimpleWasm( wasmFactory, 'pinball_physics.wasm', undefined, // editorUuid,需要在实际使用时提供 'wasm' // bundleName ); this.wasmExports = instance as WasmExports; } /** * 旧的初始化方法(保持向后兼容) */ private async initializeLegacy(): Promise { // 加载 WASM 文件 const wasmPath = 'assets/wasm/pinball_physics.wasm'; const wasmResponse = await fetch(wasmPath); if (!wasmResponse.ok) { throw new Error(`Failed to fetch WASM file: ${wasmResponse.statusText}`); } const wasmBytes = await wasmResponse.arrayBuffer(); // 编译 WASM 模块 this.wasmModule = await WebAssembly.compile(wasmBytes); // 创建实例 const importObject = this.createImportObject(); this.wasmInstance = await WebAssembly.instantiate(this.wasmModule, importObject); this.wasmExports = this.wasmInstance.exports as unknown as WasmExports; } /** * 检查 WASM 是否已加载 */ private ensureLoaded(): void { if (this.state !== WasmModuleState.LOADED || !this.wasmExports) { throw new Error('WASM Physics Engine not loaded. Call initialize() first.'); } } /** * 创建物理世界 */ async createWorld(gravity: Vector2): Promise { this.ensureLoaded(); const worldId = this.wasmExports!.pinball_create_world(gravity.x, gravity.y); this.worlds.set(worldId, true); this.bodies.set(worldId, new Map()); console.log(`Created physics world ${worldId} with gravity (${gravity.x}, ${gravity.y})`); return worldId; } /** * 销毁物理世界 */ async destroyWorld(worldId: WorldId): Promise { if (this.worlds.has(worldId)) { this.worlds.delete(worldId); this.bodies.delete(worldId); console.log(`Destroyed physics world ${worldId}`); } } /** * 执行物理步进 */ async step(worldId: WorldId): Promise { this.ensureLoaded(); if (!this.worlds.has(worldId)) { throw new Error(`World ${worldId} does not exist`); } this.wasmExports!.pinball_step_world(worldId); } /** * 创建动态刚体 */ async createDynamicBody(worldId: WorldId, position: Vector2, radius: number): Promise { this.ensureLoaded(); if (!this.worlds.has(worldId)) { throw new Error(`World ${worldId} does not exist`); } const bodyId = this.wasmExports!.pinball_create_dynamic_body(worldId, position.x, position.y); // 记录刚体 const worldBodies = this.bodies.get(worldId)!; worldBodies.set(bodyId, true); console.log(`Created dynamic body ${bodyId} at (${position.x}, ${position.y}) with radius ${radius}`); return bodyId; } /** * 创建静态刚体(暂时使用动态刚体实现) */ async createStaticBody(worldId: WorldId, position: Vector2, radius: number): Promise { // 目前 WASM 中只有 pinball_create_dynamic_body,后续可以扩展 return this.createDynamicBody(worldId, position, radius); } /** * 销毁刚体(目前 WASM 中没有此函数,仅从记录中移除) */ async destroyBody(worldId: WorldId, bodyId: BodyId): Promise { const worldBodies = this.bodies.get(worldId); if (worldBodies && worldBodies.has(bodyId)) { worldBodies.delete(bodyId); console.log(`Removed body ${bodyId} from tracking (WASM destroy not implemented yet)`); } } /** * 获取刚体位置 */ async getBodyPosition(worldId: WorldId, bodyId: BodyId): Promise { this.ensureLoaded(); const worldBodies = this.bodies.get(worldId); if (!worldBodies || !worldBodies.has(bodyId)) { return null; } const x = this.wasmExports!.pinball_get_body_x(worldId, bodyId); const y = this.wasmExports!.pinball_get_body_y(worldId, bodyId); return { x, y }; } /** * 设置刚体位置(目前 WASM 中没有此函数) */ async setBodyPosition(worldId: WorldId, bodyId: BodyId, position: Vector2): Promise { // 目前 WASM 中没有 pinball_set_body_position 函数 console.warn('setBodyPosition not implemented in WASM yet'); } /** * 获取刚体速度(目前 WASM 中没有此函数) */ async getBodyVelocity(worldId: WorldId, bodyId: BodyId): Promise { // 目前 WASM 中没有速度获取函数 console.warn('getBodyVelocity not implemented in WASM yet'); return { x: 0, y: 0 }; } /** * 设置刚体速度(目前 WASM 中没有此函数) */ async setBodyVelocity(worldId: WorldId, bodyId: BodyId, velocity: Vector2): Promise { // 目前 WASM 中没有 pinball_set_body_velocity 函数 console.warn('setBodyVelocity not implemented in WASM yet'); } /** * 获取所有物理体数据 */ async getAllBodies(worldId: WorldId): Promise { const worldBodies = this.bodies.get(worldId); if (!worldBodies) { return []; } const bodiesData: PhysicsBodyData[] = []; for (const bodyId of worldBodies.keys()) { const position = await this.getBodyPosition(worldId, bodyId); const velocity = await this.getBodyVelocity(worldId, bodyId); if (position && velocity) { bodiesData.push({ id: bodyId, position, velocity, rotation: 0, angularVelocity: 0, bodyType: 'circle', radius: 0.5, // 默认半径,可以后续改进 isStatic: false // 可以根据需要区分静态和动态 }); } } return bodiesData; } /** * 创建圆形刚体 (新接口方法) */ createCircle(options: import('../Core/IPhysicsEngine').CreateCircleOptions): BodyId { this.ensureLoaded(); // 由于目前使用第一个世界,获取第一个世界ID const firstWorldId = this.worlds.keys().next().value; if (firstWorldId === undefined) { throw new Error('No physics world created'); } // 目前WASM只支持动态刚体创建 const bodyId = this.wasmExports!.pinball_create_dynamic_body(firstWorldId, options.position.x, options.position.y); this.bodies.get(firstWorldId)!.set(bodyId, true); return bodyId; } /** * 创建矩形刚体 (新接口方法) */ createBox(options: import('../Core/IPhysicsEngine').CreateBoxOptions): BodyId { this.ensureLoaded(); const firstWorldId = this.worlds.keys().next().value; if (firstWorldId === undefined) { throw new Error('No physics world created'); } // 目前WASM只支持动态刚体创建,矩形用动态刚体模拟 const bodyId = this.wasmExports!.pinball_create_dynamic_body(firstWorldId, options.position.x, options.position.y); this.bodies.get(firstWorldId)!.set(bodyId, true); return bodyId; } /** * 移除刚体 (新接口方法) */ removeBody(bodyId: BodyId): void { // 查找包含此bodyId的世界 for (const [worldId, worldBodies] of this.bodies) { if (worldBodies.has(bodyId)) { worldBodies.delete(bodyId); // 注意:这里需要WASM支持删除函数 // this.wasmExports!.pinball_remove_body(worldId, bodyId); console.log(`Body ${bodyId} removed from world ${worldId}`); return; } } } /** * 获取刚体数据 (新接口方法) */ getBodyData(bodyId: BodyId): PhysicsBodyData | null { // 查找包含此bodyId的世界 for (const [worldId, worldBodies] of this.bodies) { if (worldBodies.has(bodyId)) { // 这里需要同步调用WASM函数获取数据 try { const x = this.wasmExports!.pinball_get_body_x(worldId, bodyId); const y = this.wasmExports!.pinball_get_body_y(worldId, bodyId); // WASM暂时不支持速度获取,使用默认值 const vx = 0; const vy = 0; return { id: bodyId, position: { x, y }, velocity: { x: vx, y: vy }, rotation: 0, // 暂时固定值 angularVelocity: 0, // 暂时固定值 bodyType: 'circle', radius: 0.5, // 暂时固定值 isStatic: false // 暂时固定值 }; } catch (error) { console.error(`Failed to get body data for body ${bodyId}:`, error); return null; } } } return null; } /** * 清理资源 (新接口方法) */ cleanup(): void { this.dispose(); // 异步转同步 } /** * 清理资源 */ async dispose(): Promise { this.worlds.clear(); this.bodies.clear(); this.wasmInstance = null; this.wasmExports = null; this.wasmModule = null; this.state = WasmModuleState.UNLOADED; console.log('WASM Physics Engine disposed'); } /** * 获取当前状态 */ getState(): WasmModuleState { return this.state; } /** * 检查平台是否支持WASM(使用WasmLoader) */ isWasmSupported(): boolean { return wasmLoader.isWasmSupported(); } /** * 获取推荐的加载策略 */ getRecommendedStrategy(): 'wasm' | 'asm' | 'unsupported' { return wasmLoader.getRecommendedStrategy(); } }