路线阶段:Unity WebGL 小游戏实战第 9 章。
本章目标:从“卡了再修”转为“预算驱动的持续优化”。
学习目标
完成本章后,你应该能做到:
- 为 WebGL 项目建立 CPU/GPU/内存/加载四维性能预算。
- 快速定位热点并制定分层优化动作。
- 通过对象池、批处理、资源裁剪稳定帧时间。
- 建立性能回归基线,避免版本迭代回退。
性能预算(首版建议)
目标设备:中端笔记本浏览器 + 主流桌面浏览器。
- 帧率目标:
60fps,最低不低于45fps。 - CPU 主线程预算:
< 10ms(稳态),峰值< 16ms。 - Draw Calls:常态
< 220,高峰< 320。 - 内存峰值:
< 420MB。 - 首屏可交互时间:
< 8s(冷启动)。
分层诊断方法
1. CPU
重点看:
- AI 决策循环
- 波次生成与销毁
- UI 重建
- 物理查询
2. GPU
重点看:
- 透明层过绘
- 材质切换导致批次拆分
- 阴影和后处理开销
3. 内存
重点看:
- 临时分配(每帧new)
- 资源驻留上限
- 场景切换后是否回落
4. 加载
重点看:
- 首包体积
- 首战资源预热缺失
- 网络失败重试与缓存策略
CPU 热路径优化
1. 降频更新
public sealed class ThrottledSystem : IUpdatable
{
public int Order { get { return 280; } }
private readonly float _interval;
private float _acc;
private readonly Action<float> _onTick;
public ThrottledSystem(float interval, Action<float> onTick)
{
_interval = interval;
_onTick = onTick;
}
public void Tick(float dt, float unscaledDt)
{
_acc += dt;
if (_acc < _interval) return;
var step = _acc;
_acc = 0f;
_onTick(step);
}
}
适用:远距离敌人 AI、低频统计、活动倒计时刷新。
2. 批量物理查询
避免每个敌人单独射线,改为帧内分批查询或共享结果缓存。
3. 禁止每帧 LINQ/字符串拼接
日志、UI 文案统一节流和缓存格式化。
GPU 优化
1. 合批策略
- 同类敌人统一材质。
- UI 图集化,减少 Canvas 切割。
- 特效分层,控制同时激活数量。
2. 过绘治理
- 减少全屏透明特效持续叠加。
- 降低大面积半透明UI层级。
- 远景特效改低配版本。
3. 阴影策略
WebGL 首版建议:
- 主角色保留关键阴影。
- 普通敌人关闭实时阴影,使用投影贴图。
内存治理
1. 临时对象池化
public sealed class TempListScope<T> : IDisposable
{
public List<T> List;
private TempListScope(List<T> list)
{
List = list;
}
public static TempListScope<T> Rent()
{
return new TempListScope<T>(ListPool<T>.Get());
}
public void Dispose()
{
ListPool<T>.Release(List);
List = null;
}
}
2. 资源回收窗口
- 关卡结算时
UnloadUnusedAssets。 - 切场景后延迟一帧再触发 GC。
- 长局中按阈值触发轻量回收。
3. 对象池容量上限
池化不是无限扩张,需有上限与裁剪规则。
加载优化
- 关键资源前置预热(技能特效、命中音效、结算UI)。
- 非关键资源延迟加载。
- 分阶段进度展示,减少“假卡死”感知。
性能埋点
每 5 秒记录一次:
- 平均帧时长
- 95分位帧时长
- Draw Calls
- 活跃敌人数
- 内存估计值
FoundationLog.Info("Perf",
"fps=" + fps +
" p95=" + p95Ms +
" draw=" + drawCalls +
" aliveEnemy=" + aliveEnemy +
" mem=" + memMb);
性能回归测试
建立 3 个固定压测场景:
- 普通局(20敌人)
- 高压局(40敌人+密集特效)
- Boss局(演出+召唤)
每次版本发版前自动记录指标并对比基线。
与前面系统联动
- 导演系统:依据性能预算动态限制
MaxAliveEnemy。 - 资源系统:按场景分组加载和释放。
- UI系统:关键面板节流更新。
- 埋点系统:输出性能趋势到看板。
WebGL 特殊注意
- 浏览器标签页切换会影响帧率统计,需要过滤无效样本。
- 不同浏览器性能差异大,基线要分浏览器类型。
- 避免依赖编辑器下的性能表现做最终结论。
验收清单
- 高压场景帧率达到预算目标。
- 版本升级后性能基线未明显回退。
- 内存峰值可控且关卡结束后可回落。
- 加载阶段用户可感知进度,不出现长时间无反馈。
常见坑
坑 1:只看平均帧率
P95/P99 才能反映卡顿体感。
坑 2:一次性做大量优化不验证
应分批验证,避免功能回归。
坑 3:优化与玩法系统强耦合
建议通过参数和中间层控制,减少业务侵入。
本月作业
完成“性能预算守门器”:
- 为三种压测场景设定阈值。
- 自动导出性能报告与版本对比。
- 若超阈值,构建流程给出阻断提示。
下一章进入 Unity WebGL 小游戏实战 10:发布运维与版本回滚(灰度、监控、快速止损)。