首页 > 解决方案 > 如何使跟随 Ai 在基于环形 2D 网格的地图上工作

问题描述

我在 2D 矩阵中有一些环绕的 NPC,我必须让它们使用环形地图跟随敌方派系 NPC。

我尝试了几种解决方案,但它们都给了我奇怪的行为,只对网格的某个值xy值起作用,然后而不是跟随它们返回一个图块。

这就是我现在要决定走哪条路:

public Position GetNextStepTowards(Position origin, Position target)
{
    Position nextStep = new Position(0, 0);

    float dx = MathF.Abs(target.X - origin.X);
    float dy = MathF.Abs(target.Y - origin.Y);

    if (dx > mapXSize / 2) nextStep.X = -1;
    else if (dx < mapXSize / 2) nextStep.X = 1;

    if (dy > mapYSize / 2) nextStep.Y = 1;
    else if (dy < mapYSize / 2) nextStep.Y = -1;

    return nextStep;
}

一个职位是:

public struct Position
{
    public int X { get; set; }
    public int Y { get; set; }

    public Position(int x, int y)
    {
        this.X = x;
        this.Y = y;
    }
}

NPC 只能移动一个单元格(Moore's),因此移动向量应该只能是 和 之间的-11

提前感谢您的帮助!

标签: c#grid2dartificial-intelligenceconsole-application

解决方案


如果我们考虑X轴,有两种情况,如下图所示:

在此处输入图像描述

在第一种情况下(顶部),目标位于原点的右侧。在这种情况下,向右移动是直接的,向左移动是环形的。

在第二种情况下(底部),目标位于原点的左侧。在这种情况下,向左移动是直接的,向右移动是环形的。

所以代码需要检查原点和目标的相对位置,然后适当的计算左右距离。较小的距离决定了 deltaX 的方向和大小。相同的逻辑适用于 deltaY。

然后如果 deltaX 和 deltaY 具有相同的大小,我们沿着对角线移动。否则,我们将朝着具有较大增量的方向移动。

private int ComputeDelta(int src, int dst, int mapSize)
{
    int increasing, decreasing;
    if (dst >= src)
    {
        increasing = dst - src;               // increasing direction is direct
        decreasing = (mapSize + src) - dst;   // decreasing direction is toroidal
    }
    else
    {
        increasing = (mapSize + dst) - src;   // increasing direction is toroidal
        decreasing = src - dst;               // decreasing direction is direct
    }

    if (increasing <= decreasing) { return  increasing; }
    else                          { return -decreasing; }
}

public Position GetNextStepTowards(Position origin, Position target)
{
    Position nextStep = new Position(0, 0);

    // compute the distances
    int dx = ComputeDelta(origin.X, target.X, mapXSize);
    int dy = ComputeDelta(origin.Y, target.Y, mapYSize);

    // keep the dominant distance, and clear the other distance
    // keep both if they're equal
    if      (dx*dx > dy*dy) { dy = 0; }
    else if (dx*dx < dy*dy) { dx = 0; }

    // normalize the distances so they are -1, 0, or 1
    nextStep.X = dx.CompareTo(0);
    nextStep.Y = dy.CompareTo(0);

    return nextStep;
}

推荐阅读