12 KiB
12 KiB
微信小游戏性能优化指南
📊 性能指标要求
微信官方标准
- 启动时间:冷启动 < 3秒,热启动 < 1秒
- 首屏渲染:< 2秒
- 帧率:稳定 60 FPS(低端机可降至 30 FPS)
- 内存占用:< 200 MB(iOS),< 300 MB(Android)
- 包体大小:主包 ≤ 20 MB,总包 ≤ 200 MB
🎯 关键优化点
1. 包体优化
代码分包策略
// project.json 配置
{
"subpackages": [
{
"name": "core",
"root": "subpackages/core/"
},
{
"name": "levels",
"root": "subpackages/levels/",
"lazy": true // 按需加载
}
]
}
资源压缩
- 图片:使用 TinyPNG 或 ImageOptim 压缩,目标减少 50-70%
- 音频:MP3 格式,比特率 128kbps,单声道
- 纹理:使用 ASTC 格式(Android)和 PVRTC(iOS)
代码优化
// ❌ 避免:频繁创建对象
function spawnFruit() {
const fruit = new Fruit(); // 每次new会触发GC
return fruit;
}
// ✅ 推荐:使用对象池
const fruitPool: Fruit[] = [];
function spawnFruit() {
let fruit = fruitPool.pop();
if (!fruit) {
fruit = new Fruit();
}
fruit.reset();
return fruit;
}
2. 内存管理
主动触发 GC
// 在合适的时机触发垃圾回收
class GameManager {
onGameOver() {
// 清理临时对象
this.clearEffects();
this.clearBullets();
// 微信环境触发GC
if (typeof wx !== 'undefined' && wx.triggerGC) {
setTimeout(() => wx.triggerGC(), 1000);
}
}
}
资源释放策略
// 场景切换时释放资源
import { resources, AssetManager } from 'cc';
class ResourceManager {
static releaseUnusedAssets() {
// 释放未使用的资源
resources.releaseAll();
// 强制清理缓存
AssetManager.cacheManager?.clear();
}
static releaseTexture(textureName: string) {
const texture = resources.get(textureName);
if (texture) {
resources.release(textureName);
texture.destroy(); // 立即销毁
}
}
}
内存监控
// 定期检查内存使用
class MemoryMonitor {
private static checkInterval = 10000; // 10秒
static startMonitoring() {
setInterval(() => {
if (wx.getSystemInfoSync) {
const info = wx.getSystemInfoSync();
const memoryMB = (info.memoryUsage || 0) / 1024 / 1024;
if (memoryMB > 200) {
console.warn(`[Memory] 内存警告: ${memoryMB.toFixed(1)} MB`);
this.triggerCleanup();
}
}
}, this.checkInterval);
}
private static triggerCleanup() {
console.log('[Memory] 执行内存清理...');
// 1. 清理特效
// 2. 清理粒子
// 3. 触发GC
}
}
3. 渲染优化
减少 Draw Calls
// ✅ 合并相同材质的Sprite
// 将多个小水果合并到一个节点下,使用同一材质
// ❌ 避免:每个水果单独一个节点
fruit1.node.parent = rootNode;
fruit2.node.parent = rootNode;
// ✅ 推荐:使用批量渲染
const batchNode = new Node('FruitBatch');
fruit1.node.parent = batchNode;
fruit2.node.parent = batchNode;
batchNode.parent = rootNode;
合批技巧
- 相同材质的Sprite放在同一父节点下
- 使用 SpriteAtlas 打包小图
- 避免动态修改材质参数
降低 Overdraw
// 设置合理的渲染层级
camera.clearFlags = ClearFlag.SOLID | ClearFlag.DEPTH;
// 隐藏不可见对象
node.active = false; // 完全禁用
// 而不是
node.opacity = 0; // 仍然参与渲染
4. 音频优化
音频格式选择
| 类型 | 格式 | 比特率 | 声道 | 文件大小 |
|---|---|---|---|---|
| BGM | MP3 | 128kbps | 立体声 | ~2MB/分钟 |
| SFX | MP3 | 96kbps | 单声道 | ~50KB/个 |
| Voice | MP3 | 64kbps | 单声道 | ~30KB/个 |
音频管理最佳实践
class AudioManager {
// 限制同时播放的音效数量
private maxConcurrentSFX = 5;
private activeSFXCount = 0;
playSFX(name: string) {
if (this.activeSFXCount >= this.maxConcurrentSFX) {
console.warn('[Audio] 音效并发数已达上限');
return;
}
this.activeSFXCount++;
// 播放音效...
// 播放完成后递减计数
setTimeout(() => {
this.activeSFXCount--;
}, duration);
}
}
5. 网络优化
广告预加载
// 在游戏启动3秒后预加载广告
setTimeout(() => {
AdManager.preloadAds();
}, 3000);
// 关卡结束前提前准备广告
class LevelManager {
onLevelComplete() {
// 提前加载插屏广告
AdManager.preloadInterstitial();
// 显示结算界面
this.showResultPanel();
}
}
数据上报优化
// ❌ 避免:频繁上报
wx.reportAnalytics('merge', { level: 1 }); // 每次合成
// ✅ 推荐:批量上报
class AnalyticsManager {
private eventQueue: any[] = [];
recordMerge(level: number) {
this.eventQueue.push({
event: 'merge',
data: { level },
timestamp: Date.now()
});
// 每10个事件或每30秒上报一次
if (this.eventQueue.length >= 10) {
this.flushEvents();
}
}
private flushEvents() {
this.eventQueue.forEach(event => {
wx.reportAnalytics(event.event, event.data);
});
this.eventQueue = [];
}
}
🔧 微信开发者工具调试
性能面板使用
- 打开微信开发者工具
- 点击「调试器」→「Performance」
- 观察以下指标:
- FPS 曲线
- 内存占用
- Draw Calls
- JS 执行时间
真机测试
# 1. 构建微信小游戏
cocos build --platform wechatgame --output ./build
# 2. 用微信开发者工具打开 build 目录
# 3. 点击「预览」生成二维码
# 4. 用手机微信扫码,在真机上测试
性能问题定位
// 添加性能埋点
class PerformanceTracker {
private static marks: Map<string, number> = new Map();
static mark(name: string) {
this.marks.set(name, performance.now());
}
static measure(name: string): number {
const start = this.marks.get(name);
if (!start) return 0;
const duration = performance.now() - start;
console.log(`[Perf] ${name}: ${duration.toFixed(2)}ms`);
return duration;
}
}
// 使用示例
PerformanceTracker.mark('levelLoadStart');
// ... 加载关卡 ...
PerformanceTracker.measure('levelLoad');
📱 低端机适配
检测低端设备
class DeviceDetector {
static isLowEndDevice(): boolean {
if (!wx.getSystemInfoSync) return false;
const info = wx.getSystemInfoSync();
// CPU核心数 ≤ 2
if (info.cpuNum <= 2) return true;
// 内存 ≤ 2GB
if (info.totalMemory <= 2 * 1024 * 1024 * 1024) return true;
// 旧款iPhone
if (info.model.includes('iPhone 6') ||
info.model.includes('iPhone 7')) {
return true;
}
return false;
}
static applyLowEndSettings() {
console.log('[Device] 应用低端机优化设置...');
// 降低目标帧率
GAME_CONFIG.targetFPS = 30;
// 减少最大水果数量
GAME_CONFIG.maxFruitsOnScreen = 25;
// 禁用部分特效
GAME_CONFIG.enableParticles = false;
// 降低音频质量
AudioManager.getInstance().setSFXVolume(0.5);
}
}
分级画质设置
enum QualityLevel {
Low,
Medium,
High
}
class QualitySettings {
static apply(level: QualityLevel) {
switch (level) {
case QualityLevel.Low:
// 低画质
this.setMaxParticles(10);
this.setShadowEnabled(false);
this.setAntiAliasing(false);
break;
case QualityLevel.Medium:
// 中画质
this.setMaxParticles(30);
this.setShadowEnabled(true);
this.setAntiAliasing(false);
break;
case QualityLevel.High:
// 高画质
this.setMaxParticles(50);
this.setShadowEnabled(true);
this.setAntiAliasing(true);
break;
}
}
}
🚀 构建发布流程
1. 构建前检查清单
- 移除所有
console.log(或使用条件编译) - 压缩所有图片和音频
- 测试广告位ID是否正确
- 验证存档系统正常
- 检查内存泄漏(长时间运行测试)
2. 构建命令
# Cocos Creator 命令行构建
cocos build \
--platform wechatgame \
--output ./build/wechatgame \
--debug false \
--compress true
3. 上传到微信后台
# 使用微信开发者工具命令行上传
wechat-miniprogram auto \
--project ./build/wechatgame \
--appid wxb2b7651c561f9d53 \
--version 1.0.0 \
--desc "报恩榴莲v1.0.0"
4. 提交审核
- 登录微信公众平台
- 进入「版本管理」
- 选择刚上传的版本
- 填写审核信息:
- 游戏简介
- 分类:休闲 → 益智
- 截图:5张 gameplay 截图
- 提交审核
🐛 常见问题排查
Q1: 游戏启动慢
原因:资源加载过多
解决:
- 使用分包加载
- 延迟加载非核心资源
- 压缩图片和音频
Q2: 内存持续增长
原因:对象未正确释放
解决:
// 确保在场景切换时清理
onDestroy() {
this.node.removeAllChildren();
resources.releaseAll();
if (wx.triggerGC) wx.triggerGC();
}
Q3: 帧率不稳定
原因:Draw Calls 过多或逻辑太重
解决:
- 合并相同材质的Sprite
- 使用对象池
- 优化碰撞检测算法
Q4: 广告不显示
原因:广告位ID错误或未真机测试
解决:
- 确认广告位ID已替换
- 必须在真机测试(模拟器不显示广告)
- 检查网络连接
📈 性能监控建议
关键指标
class MetricsCollector {
private metrics = {
fps: 0,
memory: 0,
drawCalls: 0,
avgFrameTime: 0,
};
collect() {
// FPS
this.metrics.fps = director.getScheduler().getFramesPerSecond();
// 内存
if (wx.getSystemInfoSync) {
this.metrics.memory = wx.getSystemInfoSync().memoryUsage;
}
// 上报
if (this.shouldReport()) {
wx.reportAnalytics('perf_metrics', this.metrics);
}
}
}
异常监控
// 全局错误捕获
window.onerror = function(msg, url, line, col, error) {
console.error('[Error]', msg, 'at', line, ':', col);
// 上报错误
wx.reportAnalytics('js_error', {
message: msg,
line: line,
column: col,
stack: error?.stack
});
return false;
};
✨ 总结
优化优先级
- P0:包体大小(必须 ≤ 20MB 主包)
- P0:内存管理(防止崩溃)
- P1:帧率稳定(60 FPS)
- P1:启动速度(< 3秒)
- P2:Draw Calls 优化
- P2:音频优化
持续改进
- 每周分析性能数据
- 根据用户反馈调整难度
- A/B 测试广告频控策略
- 监控留存率和通关率
最后更新:2026-08-14
适用版本:Cocos Creator 3.8 + 微信小游戏