微信小游戏适配器
微信小游戏平台适配器专为微信小游戏环境设计,处理微信小游戏的特殊限制和API。
| 特性 | 支持情况 | 说明 |
|---|---|---|
| Worker | ✅ 支持 | 需要使用预编译文件,配置 workerScriptPath |
| SharedArrayBuffer | ❌ 不支持 | 微信小游戏环境不支持 |
| Transferable Objects | ❌ 不支持 | 只支持可序列化对象 |
| 高精度时间 | ✅ 支持 | 使用 wx.getPerformance() |
| 设备信息 | ✅ 支持 | 完整的微信小游戏设备信息 |
WorkerEntitySystem 使用方式
Section titled “WorkerEntitySystem 使用方式”重要:微信小游戏 Worker 限制
Section titled “重要:微信小游戏 Worker 限制”微信小游戏的 Worker 有以下限制:
- Worker 脚本必须在代码包内,不能动态生成
- 必须在
game.json中配置workers目录 - 最多只能创建 1 个 Worker
因此,使用 WorkerEntitySystem 时有两种方式:
- 推荐:使用 CLI 工具自动生成 Worker 文件
- 手动创建 Worker 文件
方式一:使用 CLI 工具自动生成(推荐)
Section titled “方式一:使用 CLI 工具自动生成(推荐)”我们提供了 @esengine/worker-generator 工具,可以自动从你的 TypeScript 代码中提取 workerProcess 函数并生成微信小游戏兼容的 Worker 文件。
pnpm add -D @esengine/worker-generator# 或npm install --save-dev @esengine/worker-generator# 扫描 src 目录,生成 Worker 文件到 workers 目录npx esengine-worker-gen --src ./src --out ./workers --wechat
# 查看帮助npx esengine-worker-gen --help| 参数 | 说明 | 默认值 |
|---|---|---|
-s, --src <dir> | 源代码目录 | ./src |
-o, --out <dir> | 输出目录 | ./workers |
-w, --wechat | 生成微信小游戏兼容代码 | false |
-m, --mapping | 生成 worker-mapping.json | true |
-t, --tsconfig <path> | TypeScript 配置文件路径 | 自动查找 |
-v, --verbose | 详细输出 | false |
🔧 ESEngine Worker Generator
Source directory: /project/srcOutput directory: /project/workersWeChat mode: Yes
Scanning for WorkerEntitySystem classes...
✓ Found 1 WorkerEntitySystem class(es): - PhysicsSystem (src/systems/PhysicsSystem.ts)
Generating Worker files...
✓ Successfully generated 1 Worker file(s): - PhysicsSystem -> workers/physics-system-worker.js
📝 Usage:1. Copy the generated files to your project's workers/ directory2. Configure game.json (WeChat): { "workers": "workers" }3. In your System constructor, add: workerScriptPath: 'workers/physics-system-worker.js'在构建流程中集成
Section titled “在构建流程中集成”{ "scripts": { "build:workers": "esengine-worker-gen --src ./src --out ./workers --wechat", "build": "pnpm build:workers && your-build-command" }}方式二:手动创建 Worker 文件
Section titled “方式二:手动创建 Worker 文件”如果你不想使用 CLI 工具,也可以手动创建 Worker 文件。
在项目中创建 workers/entity-worker.js:
// 微信小游戏 WorkerEntitySystem 通用 Worker 模板
let sharedFloatArray = null;
worker.onMessage(function(e) { const { type, id, entities, deltaTime, systemConfig, startIndex, endIndex, sharedBuffer } = e.data;
try { // 处理 SharedArrayBuffer 初始化 if (type === 'init' && sharedBuffer) { sharedFloatArray = new Float32Array(sharedBuffer); worker.postMessage({ type: 'init', success: true }); return; }
// 处理 SharedArrayBuffer 数据 if (type === 'shared' && sharedFloatArray) { processSharedArrayBuffer(startIndex, endIndex, deltaTime, systemConfig); worker.postMessage({ id, result: null }); return; }
// 传统处理方式 if (entities) { const result = workerProcess(entities, deltaTime, systemConfig);
// 处理 Promise 返回值 if (result && typeof result.then === 'function') { result.then(function(finalResult) { worker.postMessage({ id, result: finalResult }); }).catch(function(error) { worker.postMessage({ id, error: error.message }); }); } else { worker.postMessage({ id, result: result }); } } } catch (error) { worker.postMessage({ id, error: error.message }); }});
/** * 实体处理函数 - 根据你的业务逻辑修改此函数 * @param {Array} entities - 实体数据数组 * @param {number} deltaTime - 帧间隔时间 * @param {Object} systemConfig - 系统配置 * @returns {Array} 处理后的实体数据 */function workerProcess(entities, deltaTime, systemConfig) { // ====== 在这里编写你的处理逻辑 ====== // 示例:物理计算 return entities.map(function(entity) { // 应用重力 entity.vy += (systemConfig.gravity || 100) * deltaTime;
// 更新位置 entity.x += entity.vx * deltaTime; entity.y += entity.vy * deltaTime;
// 应用摩擦力 entity.vx *= (systemConfig.friction || 0.95); entity.vy *= (systemConfig.friction || 0.95);
return entity; });}
/** * SharedArrayBuffer 处理函数(可选) */function processSharedArrayBuffer(startIndex, endIndex, deltaTime, systemConfig) { if (!sharedFloatArray) return;
// ====== 根据需要实现 SharedArrayBuffer 处理逻辑 ====== // 注意:微信小游戏不支持 SharedArrayBuffer,此函数通常不会被调用}步骤 2:配置 game.json
Section titled “步骤 2:配置 game.json”在 game.json 中添加 workers 配置:
{ "deviceOrientation": "portrait", "showStatusBar": false, "workers": "workers"}步骤 3:使用 WorkerEntitySystem
Section titled “步骤 3:使用 WorkerEntitySystem”import { WorkerEntitySystem, Matcher, Entity } from '@esengine/ecs-framework';
interface PhysicsData { id: number; x: number; y: number; vx: number; vy: number; mass: number;}
class PhysicsSystem extends WorkerEntitySystem<PhysicsData> { constructor() { super(Matcher.all(Transform, Velocity), { enableWorker: true, workerCount: 1, // 微信小游戏限制只能创建 1 个 Worker workerScriptPath: 'workers/entity-worker.js', // 指定预编译的 Worker 文件 systemConfig: { gravity: 100, friction: 0.95 } }); }
protected getDefaultEntityDataSize(): number { return 6; }
protected extractEntityData(entity: Entity): PhysicsData { const transform = entity.getComponent(Transform); const velocity = entity.getComponent(Velocity); const physics = entity.getComponent(Physics);
return { id: entity.id, x: transform.x, y: transform.y, vx: velocity.x, vy: velocity.y, mass: physics.mass }; }
// 注意:在微信小游戏中,此方法不会被使用 // Worker 的处理逻辑在 workers/entity-worker.js 中的 workerProcess 函数里 protected workerProcess(entities: PhysicsData[], deltaTime: number, config: any): PhysicsData[] { return entities.map(entity => { entity.vy += config.gravity * deltaTime; entity.x += entity.vx * deltaTime; entity.y += entity.vy * deltaTime; entity.vx *= config.friction; entity.vy *= config.friction; return entity; }); }
protected applyResult(entity: Entity, result: PhysicsData): void { const transform = entity.getComponent(Transform); const velocity = entity.getComponent(Velocity);
transform.x = result.x; transform.y = result.y; velocity.x = result.vx; velocity.y = result.vy; }
// SharedArrayBuffer 相关方法(微信小游戏不支持,可省略) protected writeEntityToBuffer(data: PhysicsData, offset: number): void {} protected readEntityFromBuffer(offset: number): PhysicsData | null { return null; }}临时禁用 Worker(降级到同步模式)
Section titled “临时禁用 Worker(降级到同步模式)”如果遇到问题,可以临时禁用 Worker:
class PhysicsSystem extends WorkerEntitySystem<PhysicsData> { constructor() { super(Matcher.all(Transform, Velocity), { enableWorker: false, // 禁用 Worker,使用主线程同步处理 // ... 其他配置 }); }}完整适配器实现
Section titled “完整适配器实现”import type { IPlatformAdapter, PlatformWorker, WorkerCreationOptions, PlatformConfig} from '@esengine/ecs-framework';
/** * 微信小游戏平台适配器 */export class WeChatMiniGameAdapter implements IPlatformAdapter { public readonly name = 'wechat-minigame'; public readonly version: string; private systemInfo: any;
constructor() { this.systemInfo = this.getSystemInfo(); this.version = this.systemInfo.SDKVersion || 'unknown'; }
public isWorkerSupported(): boolean { return typeof wx !== 'undefined' && typeof wx.createWorker === 'function'; }
public isSharedArrayBufferSupported(): boolean { return false; }
public getHardwareConcurrency(): number { return 1; // 微信小游戏最多 1 个 Worker }
public createWorker(scriptPath: string, options: WorkerCreationOptions = {}): PlatformWorker { if (!this.isWorkerSupported()) { throw new Error('微信小游戏环境不支持 Worker'); }
// scriptPath 必须是代码包内的文件路径 const worker = wx.createWorker(scriptPath, { useExperimentalWorker: true });
return new WeChatWorker(worker); }
public createSharedArrayBuffer(length: number): SharedArrayBuffer | null { return null; }
public getHighResTimestamp(): number { if (typeof wx !== 'undefined' && wx.getPerformance) { return wx.getPerformance().now(); } return Date.now(); }
public getPlatformConfig(): PlatformConfig { return { maxWorkerCount: 1, supportsModuleWorker: false, supportsTransferableObjects: false, maxSharedArrayBufferSize: 0, workerScriptPrefix: '', limitations: { noEval: true, // 重要:标记不支持动态脚本 requiresWorkerInit: false, memoryLimit: 512 * 1024 * 1024, workerNotSupported: false, workerLimitations: [ '最多只能创建 1 个 Worker', 'Worker 脚本必须在代码包内', '需要在 game.json 中配置 workers 路径', '需要使用 workerScriptPath 配置' ] }, extensions: { platform: 'wechat-minigame', sdkVersion: this.systemInfo.SDKVersion } }; }
private getSystemInfo(): any { if (typeof wx !== 'undefined' && wx.getSystemInfoSync) { try { return wx.getSystemInfoSync(); } catch (error) { console.warn('获取微信系统信息失败:', error); } } return {}; }}
/** * 微信 Worker 封装 */class WeChatWorker implements PlatformWorker { private _state: 'running' | 'terminated' = 'running'; private worker: any;
constructor(worker: any) { this.worker = worker; }
public get state(): 'running' | 'terminated' { return this._state; }
public postMessage(message: any, transfer?: Transferable[]): void { if (this._state === 'terminated') { throw new Error('Worker 已被终止'); } this.worker.postMessage(message); }
public onMessage(handler: (event: { data: any }) => void): void { this.worker.onMessage((res: any) => { handler({ data: res }); }); }
public onError(handler: (error: ErrorEvent) => void): void { if (this.worker.onError) { this.worker.onError(handler); } }
public terminate(): void { if (this._state === 'running') { this.worker.terminate(); this._state = 'terminated'; } }}import { PlatformManager } from '@esengine/ecs-framework';import { WeChatMiniGameAdapter } from './platform/WeChatMiniGameAdapter';
// 在游戏启动时注册适配器if (typeof wx !== 'undefined') { const adapter = new WeChatMiniGameAdapter(); PlatformManager.getInstance().registerAdapter(adapter);}官方文档参考
Section titled “官方文档参考”重要注意事项
Section titled “重要注意事项”Worker 限制
Section titled “Worker 限制”| 限制项 | 说明 |
|---|---|
| 数量限制 | 最多只能创建 1 个 Worker |
| 版本要求 | 需要基础库 1.9.90 及以上 |
| 脚本位置 | 必须在代码包内,不支持动态生成 |
| 生命周期 | 创建新 Worker 前必须先 terminate() |
- 通常限制在 256MB - 512MB
- 需要及时释放不用的资源
- 建议监听内存警告:
wx.onMemoryWarning(() => { console.warn('收到内存警告,开始清理资源'); // 清理不必要的资源});// 检查 Worker 配置const adapter = PlatformManager.getInstance().getAdapter();const config = adapter.getPlatformConfig();
console.log('Worker 支持:', adapter.isWorkerSupported());console.log('最大 Worker 数:', config.maxWorkerCount);console.log('平台限制:', config.limitations);