基于《蔚蓝》实现一个简易的2D物理系统(三)

作者:阿客
2023-05-14
7 4 0

碰撞优化

当完成框架代码,游戏可以跑起来后,随之而来的就是优化问题。优化可以从各个方面下手,而我想继续讨论性能上和操作上的一些优化处理。

从上一篇文章可以知道,做碰撞检测时,是一个碰撞体和场景内所有符合条件的碰撞体进行位置比较,那毫无疑问,如果场景中的碰撞体数量增加,检测的计算开销也会相应增加。因此,核心思路就是:减少检测时参与计算的碰撞体的数量。进一步试想下,有些碰撞体距离目标碰撞体很远,在直觉上它们肯定不会与目标碰撞体相撞,所以可以不参与计算,直接排除。对于这一情况的处理,有一种常规算法思路,叫空间划分。

空间划分是对游戏场景进行分区,而每个区域会标记那些停留在此的 GameObject,当这些 GameObject 需要进行碰撞检测时,通常情况下只需要检测和自己在同一个区域的 GameObject,或者相邻区域的 GameObject,更远区域的就不再进行检测。常见的空间划分有网格划分、四叉树、八叉树等。

起先我想采用网格划分的方法来处理。这是一个相对简单且直观的空间划分算法,将场景划分为等大的网格,碰撞体只需要检测自己所在网格和相邻网格内的其它碰撞体即可。如下图所示,场景被绿色网格划分为一块又一块,当角色和右边箱子碰撞时,实际上只需要检测自己本身所在的这个区域,或者再加上四周相邻的八个区域就行,无需知道其它区域里面有什么。

但实际上,我没有在项目中使用该算法,这也正是我想谈论的一点。在开发中,通用算法确实可以帮助我们解决不少问题,不过有时候,我们可以从项目本身的特点去考虑,看看能不能找到一些更取巧的 Trick 。

一开始考虑空间划分的原因是场景内的碰撞体偏多,而其中百分之八十都是静态墙体和地面(为表述简明,下文将两者统称为墙体)。项目的墙体是由 Tilemap 绘制的,由于摒弃了引擎自带的碰撞系统,导致墙体的每一块 tile 都是一个 Collider,于是在一个场景中,可能有三四十个墙体 Collider,两三个 Kinematic,四五个 Trigger。如果能够大幅减少墙体 Collider 的数量,那么在碰撞检测时,即便每次遍历全部的碰撞体,开销也相当小。由于 Tilemap 中 tile 的排布相当有序,所以考虑将相邻的 tile 进行融合,形成一个更大的矩形 Collider。通过一番尝试以及上网找资料,我发现 Love2D 实现了该算法。具体代码实现不在此讨论,直接阅读源码很容易理解。

上面两张图是融合 tile 的前后对比,可以很明显地看到,融合后的碰撞体数量大幅减少。可以说,这是一个简单且实用的方案,无需添加之前说的空间划分处理,尽量保持了项目的简洁。

手感优化

手感对于动作类游戏至关重要,GMTK 的视频《如何制作一个优秀的平台跳跃角色》(How to make a good platforming character)就讨论过《蔚蓝》中角色的操作手感是如何打造的。此处涉及到角色启动时的加速度、停止时的加速度(负值)、下落时的重力改变等参数,其中个人很喜欢的一个处理就是运动角色碰撞到墙体边缘时会产生一定偏移,让角色能够“滑过”边缘。笔者自己也在项目里实现了向上方向的处理,实际效果如下。

想要实现这样的效果,核心点在于当角色与墙壁发生碰撞时,需要用算法进行适当处理。首先,我们需要弄清楚如何定义边缘,当运动角色与头顶上的墙体相撞时,本质上是一个矩形和另一个矩形相交,而这两个矩形相交出的矩形的长度就很重要。如下图所示,如果是第一种情况,运动角色和墙体相交在各自的一角,那么这个时候进行滑动是非常合理的,而且从画面表现来看也很正常;但如果是第二种,实际上就是运动角色有大半部分被墙体挡住,自然就不应该去做滑动。

因此,在进行碰撞检测时,首先检测是否相交;如果相交了,再计算相交的长度;如果长度在一个设定的阈值里面,就可以让角色进行 x 方向的位移偏转,而这个偏转长度正好是相交的长度。还有一点就是,需要考虑角色运动的方向,如果角色运动的 x 方向,和碰撞墙体正好是相反的,即角色向左运动,碰到墙体的右上角,那就可以进行滑动,反之则不行。

大功告成

开始动笔写这篇文章,正是去年年末,疫情放开,自家小孩快出生的时候。小孩出生后又是一阵忙碌。自己本就是一个有些拖延的人,有时候坐在电脑前也没有动力打开文档继续,再加之还有装修房子、膝盖做手术这些林林总总的事情,导致文章一拖再拖,到现在已达半年之久。不过无论如何,我还是很庆幸自己完成了一开始设想的计划,希望以后还能继续完成后续计划,且不拖延。

本文为用户投稿,不代表 indienova 观点。

近期点赞的会员

 分享这篇文章

阿客 

想成为很棒的游戏设计师 

您可能还会对这些文章感兴趣

参与此文章的讨论

暂无关于此文章的评论。

您需要登录或者注册后才能发表评论

登录/注册