gratitude.durian.xpcool.com/WECHAT_OPTIMIZATION_GUIDE.md
2026-08-14 18:01:45 +08:00

541 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 微信小游戏性能优化指南
## 📊 性能指标要求
### 微信官方标准
- **启动时间**:冷启动 < 3秒热启动 < 1秒
- **首屏渲染**< 2秒
- **帧率**稳定 60 FPS低端机可降至 30 FPS
- **内存占用**< 200 MBiOS< 300 MBAndroid
- **包体大小**主包 20 MB总包 200 MB
---
## 🎯 关键优化点
### 1. 包体优化
#### 代码分包策略
```javascript
// project.json 配置
{
"subpackages": [
{
"name": "core",
"root": "subpackages/core/"
},
{
"name": "levels",
"root": "subpackages/levels/",
"lazy": true // 按需加载
}
]
}
```
#### 资源压缩
- **图片**使用 TinyPNG ImageOptim 压缩目标减少 50-70%
- **音频**MP3 格式比特率 128kbps单声道
- **纹理**使用 ASTC 格式Android PVRTCiOS
#### 代码优化
```typescript
// ❌ 避免:频繁创建对象
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
```typescript
// 在合适的时机触发垃圾回收
class GameManager {
onGameOver() {
// 清理临时对象
this.clearEffects();
this.clearBullets();
// 微信环境触发GC
if (typeof wx !== 'undefined' && wx.triggerGC) {
setTimeout(() => wx.triggerGC(), 1000);
}
}
}
```
#### 资源释放策略
```typescript
// 场景切换时释放资源
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(); // 立即销毁
}
}
}
```
#### 内存监控
```typescript
// 定期检查内存使用
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
```typescript
// ✅ 合并相同材质的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
```typescript
// 设置合理的渲染层级
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/ |
#### 音频管理最佳实践
```typescript
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. 网络优化
#### 广告预加载
```typescript
// 在游戏启动3秒后预加载广告
setTimeout(() => {
AdManager.preloadAds();
}, 3000);
// 关卡结束前提前准备广告
class LevelManager {
onLevelComplete() {
// 提前加载插屏广告
AdManager.preloadInterstitial();
// 显示结算界面
this.showResultPanel();
}
}
```
#### 数据上报优化
```typescript
// ❌ 避免:频繁上报
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 = [];
}
}
```
---
## 🔧 微信开发者工具调试
### 性能面板使用
1. 打开微信开发者工具
2. 点击调试器」→「Performance
3. 观察以下指标
- FPS 曲线
- 内存占用
- Draw Calls
- JS 执行时间
### 真机测试
```bash
# 1. 构建微信小游戏
cocos build --platform wechatgame --output ./build
# 2. 用微信开发者工具打开 build 目录
# 3. 点击「预览」生成二维码
# 4. 用手机微信扫码,在真机上测试
```
### 性能问题定位
```typescript
// 添加性能埋点
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');
```
---
## 📱 低端机适配
### 检测低端设备
```typescript
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);
}
}
```
### 分级画质设置
```typescript
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. 构建命令
```bash
# Cocos Creator 命令行构建
cocos build \
--platform wechatgame \
--output ./build/wechatgame \
--debug false \
--compress true
```
### 3. 上传到微信后台
```bash
# 使用微信开发者工具命令行上传
wechat-miniprogram auto \
--project ./build/wechatgame \
--appid wxb2b7651c561f9d53 \
--version 1.0.0 \
--desc "报恩榴莲v1.0.0"
```
### 4. 提交审核
1. 登录微信公众平台
2. 进入版本管理
3. 选择刚上传的版本
4. 填写审核信息
- 游戏简介
- 分类休闲 益智
- 截图5张 gameplay 截图
5. 提交审核
---
## 🐛 常见问题排查
### Q1: 游戏启动慢
**原因**资源加载过多
**解决**
- 使用分包加载
- 延迟加载非核心资源
- 压缩图片和音频
### Q2: 内存持续增长
**原因**对象未正确释放
**解决**
```typescript
// 确保在场景切换时清理
onDestroy() {
this.node.removeAllChildren();
resources.releaseAll();
if (wx.triggerGC) wx.triggerGC();
}
```
### Q3: 帧率不稳定
**原因**Draw Calls 过多或逻辑太重
**解决**
- 合并相同材质的Sprite
- 使用对象池
- 优化碰撞检测算法
### Q4: 广告不显示
**原因**广告位ID错误或未真机测试
**解决**
- 确认广告位ID已替换
- 必须在真机测试模拟器不显示广告
- 检查网络连接
---
## 📈 性能监控建议
### 关键指标
```typescript
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);
}
}
}
```
### 异常监控
```typescript
// 全局错误捕获
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;
};
```
---
## ✨ 总结
### 优化优先级
1. **P0**包体大小必须 20MB 主包
2. **P0**内存管理防止崩溃
3. **P1**帧率稳定60 FPS
4. **P1**启动速度< 3秒
5. **P2**Draw Calls 优化
6. **P2**音频优化
### 持续改进
- 每周分析性能数据
- 根据用户反馈调整难度
- A/B 测试广告频控策略
- 监控留存率和通关率
---
**最后更新**2026-08-14
**适用版本**Cocos Creator 3.8 + 微信小游戏