腾讯游戏开发精粹
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

1.7 其他需求

1.7.1 如何将角色从障碍区域中移出

在MOBA游戏中有大量的击飞、击退等技能,角色被击中难免会“卡”在障碍区域中,对于这种情况,需要能够快速地将角色移动到最近的合适位置。因为梯度表示最大的变化方向,所以可以用梯度快速查找合适位置:

如图1.11所示,n为梯度方向,r=0.5为角色半径,实线圈位于障碍物内,圆心φ=-0.1;虚线圈位于合适位置,圆心φ=0.6,0.6= r − (−0.1)。

图1.11 查找合适位置示意图

当障碍是凸区域时一次迭代就能找到合适位置,是非凸区域时一次迭代可能无法找到合适位置,而MOBA游戏地图大多是非凸区域,因此需要多次迭代,直到φ(x′)≥r时停止。以下为迭代计算合适位置的代码。

    Vector2 newPos = pos;
    for (int i = 0; i < 3; i++) {
        float SD = Sample(newPos);
        if (SD >= playerRadius)
          break;
        newPos += Gradient(newPos) * (playerRadius - SD);
    }

1.7.2 角色不能越过障碍物的远距离移动

当角色进行瞬时远距离移动,比如闪现,但又要求不能越过障碍物(能越过障碍物的情况则使用上面的方法)时,就需要进行连续碰撞检测来规避穿越障碍物的情况。建设使用圆盘投射(Disk Casting)进行规避,基于SDF的圆盘投射的优势在于迭代步进可以使用当前位置的φ值,如图1.12所示,这大大减少了迭代次数。

以下为圆盘投射计算位置的代码。

    // oriPos:原始位置,dir:冲刺方向,radius:角色半径,maxDist:最大冲刺距离
    public Vector2 DiskCast(Vector2 origin, Vector2 dir, float radius, float maxDist)
    {
        float t = 0f;
        while (true) {
          Vector2 p = origin + dir * t;
          float sd = Sample(p);
          if (sd <= radius) return p;
          t += sd - radius;
            if (t >= maxDist) return origin + dir * maxDist;
        }
      }