
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人
1.8 动态障碍物
以上介绍均建立在预生成SDF的基础上,但在MOBA游戏中英雄技能带有阻挡效果是非常常见的,会在运行时生成动态障碍物。前面提到生成整张地图SDF的计算量大,因此根据动态障碍物重新生成整张地图的SDF不现实。要解决动态障碍物的情况,我们先来看一下SDF的CSG运算规则。

那么对于动态障碍物的情况,可以使用预生成的静态地图SDF和动态障碍SDF的叠加,即取二者的交集。同时动态障碍SDF可以直接用程序表示[2],比如常用的如图1.13所示的圆盘SDF和图1.14所示的矩形SDF。

图1.13 圆盘SDF

图1.14 矩形SDF
圆盘SDF:

以下为计算圆盘SDF的代码。
// x为任意点坐标,c为圆盘中心,r为圆盘半径 float sdCircle(Vector2 x, Vector2 c, float r) { return (x - c).Length() - r; }
矩形SDF:

以下为计算矩形SDF的代码。
// x为任意点坐标,c为矩形中心,rot为矩形旋转角度,b为矩形边长 float sdBox(Vector2 x, Vector2 c, Vector2 rot, Vector2 b) { Vector2 p = Vector2.Dot(x - c, -rot); Vector2 d = Vector2.Abs(p) - b; return Mathf.Min(Mathf.Max(d.x, d.y), 0f) + Vector2.Max(d, Vector2.zero).Length(); }
盘为内部不可行走的动态阻挡,对于内部可以行走的环形阻挡则可视为外盘对内盘的补集,如图1.15所示。

图1.15 环形SDF可视为外盘对内盘的补集
对于部分英雄技能的打洞等跨越障碍物的功能,通过补集运算即可实现,非常容易。
至此,通过SDF的运算规则很好地解决了动态障碍物的问题,但程序SDF的计算量要比静态SDF查表插值的计算量大,因此不适合具有大量动态障碍物的情况。如果大量动态障碍物分布稀疏,则可以通过空间分割管理动态障碍物,从而减少程序SDF的计算次数。