我们的堡垒为什么会自己倒塌
· 阅读约 4 分钟
物理破坏类游戏有一个先于一切的承诺:你准备推倒的东西,得先是立着的。 在 ScaleSling 的早期版本里,有些堡垒在关卡加载时会发抖, 还有几座干脆在玩家瞄准第一发的时候就自己倒了。
这种事很容易怪到物理引擎头上,然后开始调摩擦力和密度,直到不再晃为止。 我们差一点就这么干了。结果查下来,没有一个原因出在引擎上。
二十四对方块,出生时就嵌在一起
每个关卡都是一张方块列表,每个方块有位置和尺寸,而这些数字全是手敲的。 一块 42 像素宽的木板,放在离邻居 32 像素的地方,就和邻居重叠了十个像素。 在屏幕上,十像素的重叠是看不出来的,精灵图看起来只是刚好挨着。
两个刚体不能占据同一块空间。模拟的第一步,引擎就会发现它们重叠, 然后用力把它们推开。玩家看到的抖动就是这一推, 而在一座高高的堆叠里,这一推足以让整座塔倒下。
一个读取所有关卡的脚本,找到了24 个关卡中有 16 个存在重叠,共 24 对, 重叠量在 3 到 11 像素之间。第二个脚本沿着重叠最少的那个轴把每一对分开, 那几乎总是关卡作者本意让它们相接的那个轴,两边各退一半距离, 并且分几轮进行,免得修好一对又造出另一对。 旋转过的方块它不碰,因为一块斜放木板的真实占地并不是它的宽和高。
少了一根桩的栅栏
有五个关卡共用一道栅栏,是从一关复制到下一关的: 一根 130 像素长的横梁,搭在一根桩子上。它的重心落在支撑点外 39 像素处。 它每次都会翻,在任何人碰它之前就掉下去 48 像素。
第一个想法是把横梁往回挪到桩子上方。试过了,结果它被推进了旁边一根更长的横梁里,更糟。 问题不在横梁太长;而是栅栏远端少了一根桩。补上这根桩,五个关卡一次全修好了。
我们怎么知道它修好了
光玩一遍、觉得看起来没问题是不够的。现在有一项稳定性检查: 把每个关卡加载进真正的物理引擎,一发都不打,等待模拟中的四秒, 然后测量每个方块移动了多远。
修复之前,有六个关卡会自己塌掉,移动最多的方块走了 48 像素。 修复之后,一个都不塌了,全场最大的移动是 10 像素, 也就是一堆方块找到静止位置时正常的沉降。 这项检查不需要浏览器,所以每次有关卡改动时它都会跑一遍。
高了一半的方块
有一个原因根本不在关卡数据里。一块要求 26 × 88 像素的木板, 进到游戏世界里变成了 26 × 131。一个碰撞半径应为 27 的巨魔,半径变成了 20。
游戏所用的框架,会让物体的物理刚体跟着图片一起缩放。 先按正确尺寸声明刚体,再缩放精灵图去适配,就等于把刚体又缩放了一次, 缩放比例是图片文件尺寸和要求尺寸之比。没有任何报错。 塔楼只是悬在离地二十像素的地方,炮弹则穿过了看上去是实心的东西。
修复方法是先定好图片的尺寸,再用一个精确的刚体把原来的替换掉。 我们能发现这个问题,唯一的办法是直接测量刚体,而不是读代码, 因为代码看起来是对的。现在每一种新物体都按这个办法检查。
还有一个坑:星星
每个关卡在拿到场上总分的 95% 时给三颗星。 这个目标值是在生成关卡时写进关卡文件的,而不是在游戏启动时算出来的。
当飞艇从六个关卡里移除后,每关都少了 900 分可摧毁的东西, 可三星目标还在要这些分。六个本可以完美通关的关卡,变成了根本做不到完美的关卡, 而这次改动看上去只是删了一个物体。 现在凡是改动关卡场上的内容,都会在同一次改动里重新计算星星。
说到底
建筑倒塌看起来像物理问题,于是很容易引来物理上的修法: 加摩擦、加重方块、放慢模拟。这些办法每一个都会掩盖真正的毛病, 还会让游戏打起来手感更差。真正的原因都是数据:手敲的坐标、复制来的栅栏、过期的数字。 找到它们的是测量,而不是调参。
ScaleSling 里的堡垒现在会一直立着,直到你把它推倒。 来推倒一座试试。
