Godot 游戏满屏就卡?一次 Brotato 实验给出的答案

一位独立实验者在弱 ARM 掌机上跑 Brotato,从约第 20 波起掉到 5 到 10 帧,先用自定义物理服务器失败,接着重做测试台架,找出三个小原因:碰撞层没分开、每帧重复计算、血液粒子未批量绘制。帧率收益均为作者自测,不是官方基准。

Godot 游戏满屏就卡?一次 Brotato 实验给出的答案
本篇导航5 个章节

在一台很弱的 ARM 掌机上,Brotato 从约第 20 波起掉到 5 到 10 帧。救回来的办法不是先重写物理引擎,而是先重做测试台架,再找出三个能逐项核查的小问题。

Brotato 主视觉图:土豆主角双持枪械、被敌人包围。Steam 商店官方图。

快速信息

  • Brotato,Blobfish 的俯视角竞技场射击游戏,用 Godot 3 开发,不是 Godot 4。

  • 本案性质:独立实验,不是 Blobfish 官方复盘。一位玩家兼开发者在弱掌机和弱手机上测试 Brotato。

  • 症状:实验者自述,在 Anbernic RG34XXSP 掌机上从约第 20 波起掉到 5 到 10 帧。

  • 第一次尝试失败了:自定义物理服务器和合批脚本在三星 A51 手机上复测,收益没有超出测量噪声。

  • 找到的三个原因:碰撞层没分开、每帧重复算的小活、血液效果一个粒子一次绘制。

  • 本文所有帧率数字均为实验者自有测试台架的结果,不是 Brotato 官方基准。

  • 来源:illarn《Game Optimization Methodology》,DEV Community,2026年10月20日。

  • 最后核实:2026年10月27日。

一台跟不上的掌机,和一次毫无作用的初版修复

Brotato 是个小游戏,但到了后期对弱硬件很不友好:一个土豆主角同时用最多 6 件武器,每波 20 到 90 秒,整局不到 30 分钟。游戏 2023 年 6 月 23 日出 1.0,售价 4.99 美元,Steam Deck 认证为 Verified。但这都不是本篇的故事。故事是一位实验者 illarn 在自己的弱设备上遇到卡顿后做了什么:Anbernic RG34XXSP,一台 ARM Linux 掌机,Brotato 从约第 20 波起掉到 5 到 10 帧。

他的第一反应是动大手术:写一个每帧重建哈希网格的自定义物理服务器,再加合批脚本。换到第二台弱设备——三星 A51 手机——复测的结果很残酷:收益没有超出测量噪声,自定义物理服务器反而让两个测试场景变差。于是 5 天实验里有 3 天不是用来继续优化,而是重做测试台架:固定场景、干跑、记录运行元数据、用物理 tick 数而不是流逝时间控制测试时长、看中位数、P95、P99 而不只看平均值。做到这一步,真正的原因才现形。

Brotato 第 6 波实机画面:俯视角竞技场里挤满敌人和伤害数字。Steam 商店官方截图。

原因一和二:本不该相遇的碰撞,和重复做的活

第一个原因是碰撞层。敌人 hitbox 和敌人碰撞区域没有分开,导致宽阶段刷出大量无效的敌人对敌人碰撞对,而真正需要的是玩家对敌人。把敌人 hitbox 移到单独的碰撞层就砍掉了这部分浪费。这个思路能迁移到 Godot 4:Inspector 里的 Collision Layer(自己在哪一层)和 Collision Mask(检测哪几层)就是同一套概念,代码侧 Godot 4.1 有 set_collision_layer_value 和 set_collision_mask_value。层号得按你自己的项目重排,本文不给你 Brotato 的层号,因为实验本身没有公布可照抄的布局。

第二个原因是每帧重复做的小活:静态地图尺寸每帧重算、没着火的角色也被查火焰扩散、已经被禁用的区域每帧又被禁用一次。几个守卫判断就修掉了。两个原因都不需要换引擎,都需要一个能分清真收益和噪声的台架——所以台架在先,修复在后。

原因三:一个粒子效果,几百次绘制调用

第三个原因是渲染。实验者称血液效果约占全部绘制调用的 30%,改用 MultiMeshInstance2D 一次绘制多个实例后,投石索第 200 波从 32.30 帧升到 40.11 帧,第 249 波从 51.95 帧升到 55.7 帧。Godot 4 里对应的选择是 MultiMeshInstance2D 或 GPUParticles2D,实验文章自己也提到了 Godot 4 及以后的这个选项。宽阶段实验也是同一个道理:作者称 Brotato 开发者已把宽阶段切到哈希网格,他实验性切回 BVH 后 AFK 场景变好、投石索场景略变差,只因 AFK 收益更大才保留。这是针对单个项目的实测,不是通用规则。结论不要照抄,测试方法才值得抄。

核心数字全部来自作者自己的台架,一句话就能说清:投石索第 200 波从 16.08 帧到 32.30 帧,第 249 波从 45.33 帧到 51.95 帧,AFK 第 150 波从 14.02 帧到 44.02 帧。总改动不到 200 行。这些都不是 Blobfish 的补丁说明,也不能当成 Brotato 的官方性能。Brotato 自己的补丁线是另一回事:1.1.8.0 升到 Godot 3.6 并做了爆炸与特效性能工作,2026 年 Paws and Claws 更新升到 Godot 3.7 dev-1,依据是 wiki 补丁记录与 GamingOnLinux 报道。这篇实验讲的是方法,不是发版说明。

周一早上照着做

  • 先在你自己的项目里搭一个固定的高负载场景,改任何东西之前先记下基线。

  • 先修台架再修代码:固定场景、干跑、运行元数据、按物理 tick 数定测试时长、看中位数加 P95、P99。

  • 一次只改一处,只保留在同一场景里中位数和 P95 同时变好的改动。

  • 把碰撞层分开,让根本不需要互检的对象不再产生碰撞对。

  • 给每帧重复的活加守卫判断:已经做过的、静态的、不适用的,直接跳过。

  • 用 MultiMeshInstance2D 批量绘制重复粒子,Godot 4 可用 GPUParticles2D,改前后都要测绘制调用数。