541 lines
12 KiB
Markdown
541 lines
12 KiB
Markdown
# 微信小游戏性能优化指南
|
||
|
||
## 📊 性能指标要求
|
||
|
||
### 微信官方标准
|
||
- **启动时间**:冷启动 < 3秒,热启动 < 1秒
|
||
- **首屏渲染**:< 2秒
|
||
- **帧率**:稳定 60 FPS(低端机可降至 30 FPS)
|
||
- **内存占用**:< 200 MB(iOS),< 300 MB(Android)
|
||
- **包体大小**:主包 ≤ 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)和 PVRTC(iOS)
|
||
|
||
#### 代码优化
|
||
```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 + 微信小游戏
|