en un clic
game-performance
优化游戏性能时使用。帧率、GC、Draw Call、对象池、分帧的通用规范。
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Menu
优化游戏性能时使用。帧率、GC、Draw Call、对象池、分帧的通用规范。
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Basé sur la classification professionnelle SOC
做 Cocos Creator 多机型/多分辨率适配时使用。Canvas、Widget、安全区。
Cocos Creator 用 AssetBundle 做分包/远程资源时使用。加载、释放、依赖、缓存。
优化 Cocos Creator 渲染性能时使用。合批、图集、动静分离、Label。
给 Cocos Creator 原生包做热更新时使用。version manifest、增量、校验、回滚。
写 Cocos Creator 动效/动画时使用。tween、Animation、Spine、性能与清理。
做 Cocos Creator 大量条目列表时使用。虚拟列表、节点复用。
| name | game-performance |
| description | 优化游戏性能时使用。帧率、GC、Draw Call、对象池、分帧的通用规范。 |
| category | gamedev |
| tags | ["性能","帧率","对象池"] |
规则: 发现性能问题的第一步是开引擎 Profiler,定位瓶颈究竟在 CPU 游戏线程、渲染线程、GPU 还是 GC;确认瓶颈后再动手,不猜测。
为什么——真实会犯的错: 帧率跌到 40 fps,直觉上以为是 Draw Call 太多,花两天做合批,结果 Profiler 一开,GPU 占用 30%,真正的问题是游戏线程里每帧跑了一段 O(n²) 的敌人感知逻辑。两天白费,且合批引入了新的材质管理复杂度。还有一种常见误判:以为是 GC 卡顿,把所有对象都对象池化,结果真正问题是 Shader 编译 spike,池化没有任何帮助反而增加了大量代码复杂度。
怎么做:
stat unit/stat fps/stat game/stat gpu 命令,GPU Visualizer 看渲染耗时。RenderingServer.get_rendering_info() 查 Draw Call 数量。规则: 子弹、爆炸特效、伤害数字、拾取物等生命周期短且高频生成的对象,必须用对象池复用;禁止在游戏主循环中对这类对象频繁 new/instantiate + destroy/queue_free。
为什么——真实会犯的错:
射击游戏里每颗子弹都 Instantiate + Destroy,1 秒 20 发,C# 的 GC 每隔几秒做一次 Gen0 收集,帧时间 spike 到 50ms,玩家感知到明显卡顿。在移动端这个问题更严重,GC pause 动辄 100ms+。关键是这种卡顿只在长时间游戏后出现,开发期单次测试根本发现不了,上线后玩家投诉才暴露。
怎么做:
ObjectPool<T> 内置实现;Godot:手动维护 Array 池;Unreal:Actor 池或配合 Niagara 的 GPU 粒子。规则: 减少 Draw Call 的核心是让渲染器批处理更多对象:相同材质/纹理的对象合批;UI 元素用图集;避免运行时频繁修改材质参数导致 batch 断开。
为什么——真实会犯的错:
UI 界面上 200 个图标,每个图标用独立的 Sprite 图片,200 个 Draw Call 全在 UI 层,移动端帧率卡死。换成图集(Texture Atlas)后降到 3 个 Draw Call,帧率立刻上来。另一个常见错误:代码里动态 material.SetColor(...) 修改颜色,Unity 遇到 SetColor 会破坏 Static Batching 并触发 materialInstance 拷贝,导致原本可以合批的几百个对象全部分开渲染,Draw Call 暴涨。
怎么做:
规则: 耗时的非实时计算(寻路重算、视野检测、大批量 AI 决策)分帧执行或使用时间片;远处对象启用 LOD 降低面数;不在视锥之外的对象关闭 Tick/Update。
为什么——真实会犯的错: 100 个 NPC 每帧同时刷新寻路,游戏线程单帧耗时从 2ms 涨到 18ms,超过 16.6ms 预算,帧率掉到 45fps。把寻路更新分散到 10 帧内依次执行(每帧处理 10 个),平均耗时回到 3.8ms,帧率稳了。另一个教训:远处 500 米外的敌人和近处敌人同频 Tick,这些 NPC 玩家根本看不清,却占用了和近处 NPC 等量的 CPU,是纯粹的浪费。
怎么做:
is_visible_in_tree() / IsActorInViewFrustum(),不在视锥外做计算。规则: 关卡/场景切换时主动卸载不再需要的资源;纹理用压缩格式(ETC2/ASTC/DXT);图集不能无限增大;音频用流式播放替代全部加载到内存。
为什么——真实会犯的错:
手游关卡切换后没有调用资源卸载,前一关的纹理还驻留内存,玩到第三关时内存超 2GB 被系统杀掉。另一个常见包体事故:美术给了 4096×4096 的无损 PNG 做 UI 背景图,没有设置平台压缩格式,一张图 64MB,包体直接超标,且加载时间比 ASTC 压缩版慢 8 倍。背景音乐用 preload 全量加载,3 首 BGM 占 120MB 内存,改成流式(AudioStream with stream enabled)后降到 5MB。
怎么做:
Resources.UnloadUnusedAssets()(Unity)或 gc.collect()(Godot),不依赖运行时自动回收。// ❌ 反例(Unity C#)— 每帧生成和销毁子弹,GC 压力极大
public class Gun : MonoBehaviour
{
public GameObject bulletPrefab;
void Update()
{
if (Input.GetKey(KeyCode.Space))
{
// 每帧 new 一个 GameObject,GC 负担
GameObject bullet = Instantiate(bulletPrefab, firePoint.position, firePoint.rotation);
Destroy(bullet, 3f); // 3 秒后销毁,触发 GC
}
}
}
// ✅ 正例(Unity C#)— ObjectPool 复用子弹,零运行时分配
using UnityEngine.Pool;
public class Gun : MonoBehaviour
{
public GameObject bulletPrefab;
private ObjectPool<Bullet> _pool;
void Awake()
{
_pool = new ObjectPool<Bullet>(
createFunc: () => Instantiate(bulletPrefab).GetComponent<Bullet>(),
actionOnGet: b => b.gameObject.SetActive(true),
actionOnRelease: b => b.gameObject.SetActive(false),
defaultCapacity: 30
);
}
void Update()
{
if (Input.GetKey(KeyCode.Space))
{
Bullet b = _pool.Get(); // ✅ 从池取,无 GC 分配
b.Init(firePoint.position, firePoint.rotation, _pool);
}
}
}
public class Bullet : MonoBehaviour
{
private ObjectPool<Bullet> _pool;
public void Init(Vector3 pos, Quaternion rot, ObjectPool<Bullet> pool)
{
transform.SetPositionAndRotation(pos, rot);
_pool = pool;
Invoke(nameof(ReturnToPool), 3f);
}
void ReturnToPool() => _pool.Release(this); // ✅ 归还池,不 Destroy
}