跳转到内容

微信小游戏适配器

微信小游戏平台适配器专为微信小游戏环境设计,处理微信小游戏的特殊限制和API。

特性支持情况说明
Worker✅ 支持需要使用预编译文件,配置 workerScriptPath
SharedArrayBuffer❌ 不支持微信小游戏环境不支持
Transferable Objects❌ 不支持只支持可序列化对象
高精度时间✅ 支持使用 wx.getPerformance()
设备信息✅ 支持完整的微信小游戏设备信息

微信小游戏的 Worker 有以下限制:

  • Worker 脚本必须在代码包内,不能动态生成
  • 必须在 game.json 中配置 workers 目录
  • 最多只能创建 1 个 Worker

因此,使用 WorkerEntitySystem 时有两种方式:

  1. 推荐:使用 CLI 工具自动生成 Worker 文件
  2. 手动创建 Worker 文件

方式一:使用 CLI 工具自动生成(推荐)

Section titled “方式一:使用 CLI 工具自动生成(推荐)”

我们提供了 @esengine/worker-generator 工具,可以自动从你的 TypeScript 代码中提取 workerProcess 函数并生成微信小游戏兼容的 Worker 文件。

Terminal window
pnpm add -D @esengine/worker-generator
# 或
npm install --save-dev @esengine/worker-generator
Terminal window
# 扫描 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.jsontrue
-t, --tsconfig <path>TypeScript 配置文件路径自动查找
-v, --verbose详细输出false
🔧 ESEngine Worker Generator
Source directory: /project/src
Output directory: /project/workers
WeChat 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/ directory
2. Configure game.json (WeChat): { "workers": "workers" }
3. In your System constructor, add:
workerScriptPath: 'workers/physics-system-worker.js'
package.json
{
"scripts": {
"build:workers": "esengine-worker-gen --src ./src --out ./workers --wechat",
"build": "pnpm build:workers && your-build-command"
}
}

如果你不想使用 CLI 工具,也可以手动创建 Worker 文件。

在项目中创建 workers/entity-worker.js

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,此函数通常不会被调用
}

game.json 中添加 workers 配置:

{
"deviceOrientation": "portrait",
"showStatusBar": false,
"workers": "workers"
}
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,使用主线程同步处理
// ... 其他配置
});
}
}
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);
}
限制项说明
数量限制最多只能创建 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);