在短短几个月内,我几乎从零搭建了驱动游戏运行的所有模块。有些东西我希望自己掌控,比如ECS架构、游戏状态的表示、更新与序列化——这些属于数据建模和软件架构,正是我的专长领域。图形渲染?没问题,是时候学习Vulkan和现代GPU编程了。音效?我亲手写了程序化合成器,顺便把空间混音器和限制器也一并搞定。用户体验?需求不多,边做边想。输入系统?已经解决了。
但物理引擎至今让我头痛欲裂,投入产出比极低。
在这里,没有任何可以用非常规、创意方式定制或发挥的空间。物理就是……物理。问题也不在数学上。
首先,默认所有计算都是O(n²)复杂度。小贴士:别为帧间更新八叉树而失眠。如果你需要检测上千颗子弹与上百个能互相碰撞的NPC之间的碰撞,直接每帧重建八叉树反而能大幅提速。没错,这些数字听起来很基础,但我又不是在打造《星战前夜》级别的太空战,100×1000的平方已经够让单个CPU核心忙得够呛了。
接着是碰撞体类型。你以为用包围球就能蒙混过关,因为它简单廉价?试试让针形或煎饼形飞船穿过小行星带而不撞进虚空吧。现在你需要AABB、OBB、BVH、胶囊体、圆角盒体,以及各种高深算法来处理它们之间的相交检测。
但至少你已经搞定简单形状了吧?对不对?那如果我启动加力燃烧室,一头撞进那群球形NPC里呢?它们会像台球一样四散飞旋,飘向太空,对吧?
错。根本没有旋转。等等,我发誓以前见过碰撞后旋转的!发生了什么?
结果发现,我的碰撞响应代码把上一帧的速度和当前帧的速度混在一起了。总之是个引入误差的Bug,导致物体会旋转——除非两个物体的绝对速度都接近零。修复一个Bug后:旋转消失了。太无聊了!旋转明明很酷!能把它弄回来吗?
当然,但旋转需要摩擦力。现在你得加入库仑摩擦项,当然还需要碰撞法线和切向速度。这些从哪来?让我们回头看看碰撞检测到底怎么运作……
几个小时后:摩擦项加上了,飞船相撞时开始旋转。但总觉得不对劲,物体偶尔会旋转过快,仿佛又一个数学错误在给系统注入能量。先放着吧,至少现在保持一致了,而且只依赖相对速度而非绝对速度。这也算进步了。
又出现新Bug:物体会相互穿透,永远无法分离。因为凭什么分离?你的冲量求解器又不管这个。之前一切正常是因为你为了简单把所有碰撞都当成球体正面碰撞。现在可不行了。你需要另一个晦涩的算法来解决。顺便,如果同时有两个以上物体碰撞呢?
……
别自己写物理引擎。你会花上几周时间只为解决基础问题,除非你在做某种需要特殊物理机制的罕见小众类型(滑雪?滑冰?……),否则根本没什么有趣、独特或富有创意的东西可定制或解决。你的物理要么快速准确,要么缓慢充满Bug,玩家要么讨厌它,要么发现一堆搞笑漏洞。
(这不算真正的经验总结。我还没放弃物理引擎,也没去研究能用哪些现成的物理引擎。)
评论 (0)