From e2cca5e4909e5c9b800373e130b54425705e5a2b Mon Sep 17 00:00:00 2001 From: yhh <359807859@qq.com> Date: Wed, 3 Dec 2025 16:18:48 +0800 Subject: [PATCH] =?UTF-8?q?feat(physics-rapier2d):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E8=B7=A8=E5=B9=B3=E5=8F=B0WASM=E5=8A=A0=E8=BD=BD=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/physics-rapier2d/module.json | 49 ++++ packages/physics-rapier2d/package.json | 3 +- .../src/PhysicsEditorPlugin.ts | 31 +-- .../src/PhysicsRuntimeModule.ts | 137 +++++++++- packages/physics-rapier2d/src/index.ts | 3 + .../src/loaders/Rapier2DLoaderConfig.ts | 59 +++++ .../src/loaders/WeChatRapier2DLoader.ts | 237 ++++++++++++++++++ .../src/loaders/WebRapier2DLoader.ts | 96 +++++++ .../physics-rapier2d/src/loaders/index.ts | 58 +++++ .../src/systems/Physics2DSystem.ts | 4 +- .../src/world/Physics2DWorld.ts | 2 +- packages/physics-rapier2d/tsup.config.ts | 2 + 12 files changed, 650 insertions(+), 31 deletions(-) create mode 100644 packages/physics-rapier2d/module.json create mode 100644 packages/physics-rapier2d/src/loaders/Rapier2DLoaderConfig.ts create mode 100644 packages/physics-rapier2d/src/loaders/WeChatRapier2DLoader.ts create mode 100644 packages/physics-rapier2d/src/loaders/WebRapier2DLoader.ts create mode 100644 packages/physics-rapier2d/src/loaders/index.ts diff --git a/packages/physics-rapier2d/module.json b/packages/physics-rapier2d/module.json new file mode 100644 index 00000000..0c6b5571 --- /dev/null +++ b/packages/physics-rapier2d/module.json @@ -0,0 +1,49 @@ +{ + "id": "physics-rapier2d", + "name": "@esengine/physics-rapier2d", + "displayName": "Physics 2D (Rapier)", + "description": "2D physics using Rapier engine | 使用 Rapier 引擎的 2D 物理", + "version": "1.0.0", + "category": "Physics", + "icon": "Atom", + "tags": [ + "physics", + "2d", + "rapier", + "collision" + ], + "isCore": false, + "defaultEnabled": false, + "isEngineModule": true, + "canContainContent": false, + "platforms": [ + "web", + "desktop" + ], + "dependencies": [ + "core", + "math" + ], + "externalDependencies": [ + "@esengine/rapier2d" + ], + "exports": { + "components": [ + "RigidBody2D", + "Collider2D", + "BoxCollider2D", + "CircleCollider2D" + ], + "systems": [ + "PhysicsSystem2D" + ] + }, + "requiresWasm": true, + "wasmPaths": [ + "rapier_wasm2d_bg.wasm" + ], + "runtimeWasmPath": "wasm/rapier_wasm2d_bg.wasm", + "outputPath": "dist/index.js", + "pluginExport": "PhysicsPlugin", + "includes": ["chunk-*.js"] +} diff --git a/packages/physics-rapier2d/package.json b/packages/physics-rapier2d/package.json index cb5686ad..99817dcb 100644 --- a/packages/physics-rapier2d/package.json +++ b/packages/physics-rapier2d/package.json @@ -41,7 +41,8 @@ "author": "yhh", "license": "MIT", "dependencies": { - "@dimforge/rapier2d-compat": "^0.14.0" + "@esengine/rapier2d": "workspace:*", + "@esengine/platform-common": "workspace:*" }, "devDependencies": { "@esengine/ecs-framework": "workspace:*", diff --git a/packages/physics-rapier2d/src/PhysicsEditorPlugin.ts b/packages/physics-rapier2d/src/PhysicsEditorPlugin.ts index f9e4afab..46c2c70f 100644 --- a/packages/physics-rapier2d/src/PhysicsEditorPlugin.ts +++ b/packages/physics-rapier2d/src/PhysicsEditorPlugin.ts @@ -4,28 +4,29 @@ * 编辑器版本的物理插件,不包含 WASM 依赖。 * Editor version of physics plugin, without WASM dependencies. * - * 用于编辑器中注册插件描述符,但不创建运行时模块。 + * 用于编辑器中注册插件清单,但不创建运行时模块。 * 运行时使用 PhysicsPlugin from '@esengine/physics-rapier2d/runtime' */ -import type { IPlugin, PluginDescriptor } from '@esengine/engine-core'; +import type { IPlugin, ModuleManifest } from '@esengine/engine-core'; -const descriptor: PluginDescriptor = { +const manifest: ModuleManifest = { id: '@esengine/physics-rapier2d', - name: 'Physics 2D', + name: '@esengine/physics-rapier2d', + displayName: 'Physics 2D', version: '1.0.0', description: 'Deterministic 2D physics with Rapier2D', - category: 'physics', - enabledByDefault: false, + category: 'Physics', + isCore: false, + defaultEnabled: false, + isEngineModule: true, canContainContent: false, - isEnginePlugin: true, - modules: [ - { - name: 'PhysicsRuntime', - type: 'runtime', - loadingPhase: 'default' - } - ] + requiresWasm: true, + dependencies: ['engine-core'], + exports: { + components: ['Rigidbody2DComponent', 'BoxCollider2DComponent', 'CircleCollider2DComponent'], + systems: ['PhysicsSystem'] + } }; /** @@ -35,6 +36,6 @@ const descriptor: PluginDescriptor = { * 编辑器使用此版本注册插件,运行时使用带 WASM 的完整版本。 */ export const Physics2DPlugin: IPlugin = { - descriptor + manifest // No runtime module - editor doesn't need physics simulation }; diff --git a/packages/physics-rapier2d/src/PhysicsRuntimeModule.ts b/packages/physics-rapier2d/src/PhysicsRuntimeModule.ts index 18fabfc1..e2034a52 100644 --- a/packages/physics-rapier2d/src/PhysicsRuntimeModule.ts +++ b/packages/physics-rapier2d/src/PhysicsRuntimeModule.ts @@ -1,7 +1,14 @@ +/** + * 物理运行时模块 + * + * 提供 Rapier2D 物理引擎的 ECS 集成 + */ + import type { IScene, ServiceContainer } from '@esengine/ecs-framework'; import { ComponentRegistry } from '@esengine/ecs-framework'; -import type { IRuntimeModule, IPlugin, PluginDescriptor, SystemContext } from '@esengine/engine-core'; -import * as RAPIER from '@dimforge/rapier2d-compat'; +import type { IRuntimeModule, IPlugin, ModuleManifest, SystemContext } from '@esengine/engine-core'; +import { WasmLibraryLoaderFactory } from '@esengine/platform-common'; +import type * as RAPIER from '@esengine/rapier2d'; import { Rigidbody2DComponent } from './components/Rigidbody2DComponent'; import { BoxCollider2DComponent } from './components/BoxCollider2DComponent'; @@ -11,21 +18,91 @@ import { PolygonCollider2DComponent } from './components/PolygonCollider2DCompon import { Physics2DSystem } from './systems/Physics2DSystem'; import { Physics2DService } from './services/Physics2DService'; +// 注册 Rapier2D 加载器 +import './loaders'; + +/** + * 物理系统上下文扩展 + */ export interface PhysicsSystemContext extends SystemContext { + /** + * 物理系统实例 + */ physicsSystem?: Physics2DSystem; + + /** + * 物理世界实例 + */ physics2DWorld?: any; + + /** + * 物理配置 + */ physicsConfig?: any; } +/** + * 物理运行时模块 + * + * 负责: + * 1. 加载并初始化 Rapier2D WASM 模块(跨平台) + * 2. 注册物理组件 + * 3. 注册物理服务 + * 4. 创建物理系统 + * + * @example + * ```typescript + * // 作为插件使用 + * runtimePluginManager.register(PhysicsPlugin); + * runtimePluginManager.enable('@esengine/physics-rapier2d'); + * + * // 插件会自动: + * // 1. 检测平台并选择合适的加载器 + * // 2. 安装必要的 polyfills(如微信小游戏的 TextDecoder) + * // 3. 加载 Rapier2D WASM 模块 + * // 4. 注册物理组件和系统 + * ``` + */ class PhysicsRuntimeModule implements IRuntimeModule { private _rapierModule: typeof RAPIER | null = null; private _physicsSystem: Physics2DSystem | null = null; + /** + * 初始化物理模块 + * + * 使用平台适配的加载器加载 Rapier2D + */ async onInitialize(): Promise { - await RAPIER.init(); - this._rapierModule = RAPIER; + // 使用工厂创建平台对应的加载器 + const loader = WasmLibraryLoaderFactory.createLoader('rapier2d'); + + // 获取平台信息 + const platformInfo = loader.getPlatformInfo(); + console.log(`[Physics] 平台: ${platformInfo.type}`); + console.log(`[Physics] WASM 支持: ${platformInfo.supportsWasm}`); + + if (platformInfo.needsPolyfills.length > 0) { + console.log(`[Physics] 需要 Polyfills: ${platformInfo.needsPolyfills.join(', ')}`); + } + + // 检查平台支持 + if (!loader.isSupported()) { + throw new Error( + `[Physics] 当前平台不支持 Rapier2D: ${platformInfo.type}。` + + '请检查 WebAssembly 支持情况。' + ); + } + + // 加载 Rapier2D + this._rapierModule = await loader.load(); + console.log('[Physics] Rapier2D 加载完成'); } + /** + * 注册物理组件 + * + * @param registry - 组件注册表 + */ registerComponents(registry: typeof ComponentRegistry): void { registry.register(Rigidbody2DComponent); registry.register(BoxCollider2DComponent); @@ -34,10 +111,21 @@ class PhysicsRuntimeModule implements IRuntimeModule { registry.register(PolygonCollider2DComponent); } + /** + * 注册物理服务 + * + * @param services - 服务容器 + */ registerServices(services: ServiceContainer): void { services.registerSingleton(Physics2DService); } + /** + * 创建物理系统 + * + * @param scene - 目标场景 + * @param context - 系统上下文 + */ createSystems(scene: IScene, context: SystemContext): void { const physicsContext = context as PhysicsSystemContext; @@ -57,32 +145,57 @@ class PhysicsRuntimeModule implements IRuntimeModule { physicsContext.physics2DWorld = physicsSystem.world; } + /** + * 销毁物理模块 + */ onDestroy(): void { this._physicsSystem = null; this._rapierModule = null; } + /** + * 获取 Rapier 模块 + * + * @returns Rapier 模块,如果未加载则返回 null + */ getRapierModule(): typeof RAPIER | null { return this._rapierModule; } + /** + * 获取物理系统 + * + * @returns 物理系统,如果未创建则返回 null + */ getPhysicsSystem(): Physics2DSystem | null { return this._physicsSystem; } } -const descriptor: PluginDescriptor = { - id: '@esengine/physics-rapier2d', - name: 'Physics 2D', +/** + * 模块清单 + */ +const manifest: ModuleManifest = { + id: 'physics-rapier2d', + name: '@esengine/physics-rapier2d', + displayName: 'Physics 2D (Rapier)', version: '1.0.0', - description: 'Deterministic 2D physics with Rapier2D', - category: 'physics', - enabledByDefault: true, - isEnginePlugin: true + description: '基于 Rapier2D 的确定性 2D 物理引擎(支持跨平台)', + category: 'Physics', + icon: 'Atom', + isCore: false, + defaultEnabled: false, + isEngineModule: true, + dependencies: ['core', 'math'], + exports: { components: ['RigidBody2D'] }, + requiresWasm: true }; +/** + * 物理插件 + */ export const PhysicsPlugin: IPlugin = { - descriptor, + manifest, runtimeModule: new PhysicsRuntimeModule() }; diff --git a/packages/physics-rapier2d/src/index.ts b/packages/physics-rapier2d/src/index.ts index 52d4bb4d..5383ab60 100644 --- a/packages/physics-rapier2d/src/index.ts +++ b/packages/physics-rapier2d/src/index.ts @@ -24,3 +24,6 @@ export type { Physics2DSystem } from './systems/Physics2DSystem'; // Editor plugin (no WASM dependency) export { Physics2DPlugin } from './PhysicsEditorPlugin'; + +// Runtime plugin (for game builds) +export { PhysicsPlugin } from './PhysicsRuntimeModule'; diff --git a/packages/physics-rapier2d/src/loaders/Rapier2DLoaderConfig.ts b/packages/physics-rapier2d/src/loaders/Rapier2DLoaderConfig.ts new file mode 100644 index 00000000..b3195b90 --- /dev/null +++ b/packages/physics-rapier2d/src/loaders/Rapier2DLoaderConfig.ts @@ -0,0 +1,59 @@ +/** + * Rapier2D 加载器配置 + * Rapier2D loader configuration + */ + +import type { WasmLibraryConfig } from '@esengine/platform-common'; +import { isEditorEnvironment } from '@esengine/platform-common'; + +/** + * 获取 WASM 路径 + * Get WASM path based on environment + */ +function getWasmPath(): string { + const isEditor = isEditorEnvironment(); + const path = isEditor + ? 'engine/physics-rapier2d/rapier_wasm2d_bg.wasm' + : 'wasm/rapier_wasm2d_bg.wasm'; + + console.log(`[Rapier2D] isEditor=${isEditor}, wasmPath=${path}`); + return path; +} + +/** + * Rapier2D 加载器配置 + * + * Web 平台:使用标准版(独立 WASM 文件) + * 小游戏平台:使用独立 WASM 文件 + WXWebAssembly 加载 + */ +export const Rapier2DLoaderConfig: WasmLibraryConfig = { + name: 'Rapier2D', + + web: { + /** + * WASM 文件路径 + * 编辑器: engine/physics-rapier2d/rapier_wasm2d_bg.wasm + * 运行时: wasm/rapier_wasm2d_bg.wasm + */ + get wasmPath(): string { + return getWasmPath(); + } + }, + + minigame: { + /** + * WASM 文件路径(相对于小游戏根目录) + */ + wasmPath: 'wasm/rapier_wasm2d_bg.wasm', + + /** + * iOS 微信小游戏需要 TextDecoder polyfill + */ + needsTextDecoderPolyfill: true, + + /** + * iOS 微信小游戏需要 TextEncoder polyfill + */ + needsTextEncoderPolyfill: true, + } +}; diff --git a/packages/physics-rapier2d/src/loaders/WeChatRapier2DLoader.ts b/packages/physics-rapier2d/src/loaders/WeChatRapier2DLoader.ts new file mode 100644 index 00000000..d66f701d --- /dev/null +++ b/packages/physics-rapier2d/src/loaders/WeChatRapier2DLoader.ts @@ -0,0 +1,237 @@ +/** + * 微信小游戏平台 Rapier2D 加载器 + * + * 使用 WXWebAssembly 加载独立的 .wasm 文件 + */ + +import type { + IWasmLibraryLoader, + WasmLibraryConfig, + PlatformInfo +} from '@esengine/platform-common'; +import { + PlatformType, + installTextDecoderPolyfill, + installTextEncoderPolyfill +} from '@esengine/platform-common'; + +/** + * Rapier2D 模块类型 + */ +type RapierModule = typeof import('@esengine/rapier2d'); + +/** + * 微信小游戏 WASM API 类型声明 + */ +declare const WXWebAssembly: { + instantiate( + path: string, + imports?: WebAssembly.Imports + ): Promise; + Memory: typeof WebAssembly.Memory; + Table: typeof WebAssembly.Table; +}; + +/** + * 微信小游戏平台 Rapier2D 加载器 + * + * 特殊处理: + * 1. 安装 TextDecoder/TextEncoder polyfill + * 2. 使用 WXWebAssembly 加载 .wasm 文件 + * 3. 临时替换全局 WebAssembly 对象 + * + * @example + * ```typescript + * const loader = new WeChatRapier2DLoader(config); + * if (loader.isSupported()) { + * const RAPIER = await loader.load(); + * // 使用 RAPIER... + * } + * ``` + */ +export class WeChatRapier2DLoader implements IWasmLibraryLoader { + private _config: WasmLibraryConfig; + + /** + * 创建微信小游戏平台 Rapier2D 加载器 + * + * @param config - 加载器配置 + */ + constructor(config: WasmLibraryConfig) { + this._config = config; + } + + /** + * 加载 Rapier2D 模块 + * + * @returns 初始化完成的 Rapier2D 模块 + */ + async load(): Promise { + console.log(`[${this._config.name}] 正在加载微信小游戏版本...`); + + // 1. 安装必要的 polyfills + this.installPolyfills(); + + // 2. 检查 WXWebAssembly 支持 + if (typeof WXWebAssembly === 'undefined') { + throw new Error( + `[${this._config.name}] 当前微信基础库版本不支持 WebAssembly,` + + '请升级微信或使用更高版本的基础库' + ); + } + + // 3. 加载 Rapier2D + const RAPIER = await this.loadRapierWithWXWasm(); + + console.log(`[${this._config.name}] 加载完成`); + return RAPIER; + } + + /** + * 安装必要的 polyfills + */ + private installPolyfills(): void { + const config = this._config.minigame; + + if (config?.needsTextDecoderPolyfill) { + installTextDecoderPolyfill(); + } + + if (config?.needsTextEncoderPolyfill) { + installTextEncoderPolyfill(); + } + } + + /** + * 使用 WXWebAssembly 加载 Rapier2D + * + * 通过临时替换全局 WebAssembly 对象来使 Rapier2D 使用 WXWebAssembly + * + * @returns 初始化完成的 Rapier2D 模块 + */ + private async loadRapierWithWXWasm(): Promise { + // 保存原始 WebAssembly 对象 + const originalWebAssembly = (globalThis as any).WebAssembly; + + try { + // 创建一个包装的 WebAssembly 对象 + // 让 Rapier2D 的初始化代码使用 WXWebAssembly + (globalThis as any).WebAssembly = this.createWXWebAssemblyWrapper(); + + // 导入 Rapier2D 标准版 + const RAPIER = await import('@esengine/rapier2d'); + + // 初始化 WASM - 标准版需要提供 WASM 路径 + const wasmPath = this._config.minigame?.wasmPath || 'wasm/rapier_wasm2d_bg.wasm'; + await RAPIER.init(wasmPath); + + return RAPIER; + } finally { + // 恢复原始 WebAssembly 对象 + if (originalWebAssembly) { + (globalThis as any).WebAssembly = originalWebAssembly; + } + } + } + + /** + * 创建 WXWebAssembly 包装器 + * + * 将 WXWebAssembly 包装成与标准 WebAssembly API 兼容的形式 + * + * @returns 包装后的 WebAssembly 对象 + */ + private createWXWebAssemblyWrapper(): typeof WebAssembly { + const wasmPath = this._config.minigame?.wasmPath || 'wasm/rapier2d_bg.wasm'; + + return { + instantiate: async ( + bufferSource: BufferSource | WebAssembly.Module, + imports?: WebAssembly.Imports + ): Promise => { + // WXWebAssembly.instantiate 直接接受文件路径 + const instance = await WXWebAssembly.instantiate(wasmPath, imports); + return { + instance, + module: {} as WebAssembly.Module + }; + }, + + instantiateStreaming: async ( + response: Response | PromiseLike, + imports?: WebAssembly.Imports + ): Promise => { + // 微信不支持 streaming,直接使用 instantiate + const instance = await WXWebAssembly.instantiate(wasmPath, imports); + return { + instance, + module: {} as WebAssembly.Module + }; + }, + + compile: async (bytes: BufferSource): Promise => { + // 微信小游戏不支持单独编译 + throw new Error('WXWebAssembly 不支持 compile 方法'); + }, + + compileStreaming: async (source: Response | PromiseLike): Promise => { + throw new Error('WXWebAssembly 不支持 compileStreaming 方法'); + }, + + validate: (bytes: BufferSource): boolean => { + // 简单返回 true,实际验证在 instantiate 时进行 + return true; + }, + + Memory: WXWebAssembly.Memory, + Table: WXWebAssembly.Table, + Global: (globalThis as any).WebAssembly?.Global, + Tag: (globalThis as any).WebAssembly?.Tag, + Exception: (globalThis as any).WebAssembly?.Exception, + CompileError: (globalThis as any).WebAssembly?.CompileError || Error, + LinkError: (globalThis as any).WebAssembly?.LinkError || Error, + RuntimeError: (globalThis as any).WebAssembly?.RuntimeError || Error, + } as unknown as typeof WebAssembly; + } + + /** + * 检查是否支持 WXWebAssembly + * + * @returns 是否支持 + */ + isSupported(): boolean { + return typeof WXWebAssembly !== 'undefined'; + } + + /** + * 获取平台信息 + * Get platform information + */ + getPlatformInfo(): PlatformInfo { + const needsPolyfills: string[] = []; + + if (typeof globalThis.TextDecoder === 'undefined') { + needsPolyfills.push('TextDecoder'); + } + if (typeof globalThis.TextEncoder === 'undefined') { + needsPolyfills.push('TextEncoder'); + } + + return { + type: PlatformType.WeChatMiniGame, + supportsWasm: typeof WXWebAssembly !== 'undefined', + supportsSharedArrayBuffer: false, + needsPolyfills, + isEditor: false // 微信小游戏不可能是编辑器环境 | WeChat cannot be editor + }; + } + + /** + * 获取加载器配置 + * + * @returns 配置对象 + */ + getConfig(): WasmLibraryConfig { + return this._config; + } +} diff --git a/packages/physics-rapier2d/src/loaders/WebRapier2DLoader.ts b/packages/physics-rapier2d/src/loaders/WebRapier2DLoader.ts new file mode 100644 index 00000000..693859e6 --- /dev/null +++ b/packages/physics-rapier2d/src/loaders/WebRapier2DLoader.ts @@ -0,0 +1,96 @@ +/** + * Web 平台 Rapier2D 加载器 + * + * 使用 @esengine/rapier2d 标准版(独立 WASM 文件) + */ + +import type { + IWasmLibraryLoader, + WasmLibraryConfig, + PlatformInfo +} from '@esengine/platform-common'; +import { PlatformType, isEditorEnvironment } from '@esengine/platform-common'; + +/** + * Rapier2D 模块类型 + */ +type RapierModule = typeof import('@esengine/rapier2d'); + +/** + * Web 平台 Rapier2D 加载器 + * + * 使用标准版,需要配置 WASM 路径 + * + * @example + * ```typescript + * const loader = new WebRapier2DLoader(config); + * if (loader.isSupported()) { + * const RAPIER = await loader.load(); + * // 使用 RAPIER... + * } + * ``` + */ +export class WebRapier2DLoader implements IWasmLibraryLoader { + private _config: WasmLibraryConfig; + + /** + * 创建 Web 平台 Rapier2D 加载器 + * + * @param config - 加载器配置 + */ + constructor(config: WasmLibraryConfig) { + this._config = config; + } + + /** + * 加载 Rapier2D 模块 + * + * @returns 初始化完成的 Rapier2D 模块 + */ + async load(): Promise { + console.log(`[${this._config.name}] 正在加载 Web 版本...`); + + // 动态导入标准版 + const RAPIER = await import('@esengine/rapier2d'); + + // 初始化 WASM - 标准版需要提供 WASM 路径 + // 构建时 WASM 文件会被复制到 wasm/ 目录 + const wasmPath = this._config.web?.wasmPath || 'wasm/rapier_wasm2d_bg.wasm'; + await RAPIER.init(wasmPath); + + console.log(`[${this._config.name}] 加载完成`); + return RAPIER; + } + + /** + * 检查是否支持 WebAssembly + * + * @returns 是否支持 + */ + isSupported(): boolean { + return typeof WebAssembly !== 'undefined'; + } + + /** + * 获取平台信息 + * Get platform information + */ + getPlatformInfo(): PlatformInfo { + return { + type: PlatformType.Web, + supportsWasm: typeof WebAssembly !== 'undefined', + supportsSharedArrayBuffer: typeof SharedArrayBuffer !== 'undefined', + needsPolyfills: [], + isEditor: isEditorEnvironment() + }; + } + + /** + * 获取加载器配置 + * + * @returns 配置对象 + */ + getConfig(): WasmLibraryConfig { + return this._config; + } +} diff --git a/packages/physics-rapier2d/src/loaders/index.ts b/packages/physics-rapier2d/src/loaders/index.ts new file mode 100644 index 00000000..6c285cec --- /dev/null +++ b/packages/physics-rapier2d/src/loaders/index.ts @@ -0,0 +1,58 @@ +/** + * Rapier2D 加载器 + * + * 提供跨平台的 Rapier2D 物理引擎加载支持 + */ + +export { Rapier2DLoaderConfig } from './Rapier2DLoaderConfig'; +export { WebRapier2DLoader } from './WebRapier2DLoader'; +export { WeChatRapier2DLoader } from './WeChatRapier2DLoader'; + +import { PlatformType, WasmLibraryLoaderFactory } from '@esengine/platform-common'; +import { Rapier2DLoaderConfig } from './Rapier2DLoaderConfig'; +import { WebRapier2DLoader } from './WebRapier2DLoader'; +import { WeChatRapier2DLoader } from './WeChatRapier2DLoader'; + +/** + * 注册 Rapier2D 加载器到工厂 + * + * 在模块加载时自动执行 + */ +export function registerRapier2DLoaders(): void { + // Web 平台加载器 + WasmLibraryLoaderFactory.registerLoader( + 'rapier2d', + PlatformType.Web, + () => new WebRapier2DLoader(Rapier2DLoaderConfig) + ); + + // 微信小游戏平台加载器 + WasmLibraryLoaderFactory.registerLoader( + 'rapier2d', + PlatformType.WeChatMiniGame, + () => new WeChatRapier2DLoader(Rapier2DLoaderConfig) + ); + + // 其他小游戏平台可以复用微信加载器(API 类似) + // 如果需要特殊处理,可以创建专门的加载器 + WasmLibraryLoaderFactory.registerLoader( + 'rapier2d', + PlatformType.ByteDanceMiniGame, + () => new WeChatRapier2DLoader(Rapier2DLoaderConfig) + ); + + WasmLibraryLoaderFactory.registerLoader( + 'rapier2d', + PlatformType.AlipayMiniGame, + () => new WeChatRapier2DLoader(Rapier2DLoaderConfig) + ); + + WasmLibraryLoaderFactory.registerLoader( + 'rapier2d', + PlatformType.BaiduMiniGame, + () => new WeChatRapier2DLoader(Rapier2DLoaderConfig) + ); +} + +// 模块加载时自动注册 +registerRapier2DLoaders(); diff --git a/packages/physics-rapier2d/src/systems/Physics2DSystem.ts b/packages/physics-rapier2d/src/systems/Physics2DSystem.ts index 151c12cb..29380243 100644 --- a/packages/physics-rapier2d/src/systems/Physics2DSystem.ts +++ b/packages/physics-rapier2d/src/systems/Physics2DSystem.ts @@ -56,7 +56,7 @@ export interface Physics2DSystemConfig { */ export class Physics2DSystem extends EntitySystem { private _world: Physics2DWorld; - private _rapierModule: typeof import('@dimforge/rapier2d-compat') | null = null; + private _rapierModule: typeof import('@esengine/rapier2d') | null = null; private _rapierInitialized: boolean = false; private _config: Physics2DSystemConfig; @@ -102,7 +102,7 @@ export class Physics2DSystem extends EntitySystem { * * @param rapier Rapier2D 模块 */ - public async initializeWithRapier(rapier: typeof import('@dimforge/rapier2d-compat')): Promise { + public async initializeWithRapier(rapier: typeof import('@esengine/rapier2d')): Promise { if (this._rapierInitialized) { this.logger.warn('Physics2DSystem already initialized'); return; diff --git a/packages/physics-rapier2d/src/world/Physics2DWorld.ts b/packages/physics-rapier2d/src/world/Physics2DWorld.ts index 64c5bcf6..8dec8819 100644 --- a/packages/physics-rapier2d/src/world/Physics2DWorld.ts +++ b/packages/physics-rapier2d/src/world/Physics2DWorld.ts @@ -5,7 +5,7 @@ * 封装 Rapier2D 物理世界,提供确定性物理模拟 */ -import type RAPIER from '@dimforge/rapier2d-compat'; +import type RAPIER from '@esengine/rapier2d'; import type { Physics2DConfig, Vector2, diff --git a/packages/physics-rapier2d/tsup.config.ts b/packages/physics-rapier2d/tsup.config.ts index aca96ccf..4a70a3bd 100644 --- a/packages/physics-rapier2d/tsup.config.ts +++ b/packages/physics-rapier2d/tsup.config.ts @@ -2,6 +2,8 @@ import { defineConfig } from 'tsup'; import { STANDARD_EXTERNALS } from '../build-config/src/types'; // Physics-rapier2d keeps runtime entry for WASM loading +// Chunks are shared between index and runtime entries +// 保留 chunk 分割,index 和 runtime 入口共享代码 export default defineConfig({ entry: { index: 'src/index.ts',