我在一个环绕的2D矩阵中有一些NPC,我需要让它们在环形地图上追踪敌对派系的NPC。
我尝试了几种解决方案,但它们都表现出奇怪的行为,只在网格的特定x
或y
值范围内有效,然后NPC不是继续追踪而是返回一个格子。
这是我目前决定移动方向的代码:
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;}
Position结构如下:
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只能移动一个格子(摩尔邻域),因此移动向量的值应在-1
和1
之间。
提前感谢您的帮助!
回答:
如果我们考虑X轴,有两种情况,如下图所示:
在第一种情况(上图)中,目标在原点的右侧。在这种情况下,向右移动是直接的,向左移动是环形的。
在第二种情况(下图)中,目标在原点的左侧。在这种情况下,向左移动是直接的,向右移动是环形的。
因此,代码需要检查原点和目标的相对位置,然后适当计算左右距离。较小的距离决定deltaX的方向和大小。deltaY的逻辑相同。
然后,如果deltaX和deltaY的大小相同,我们沿对角线移动。否则,我们向delta值较大的方向移动。
private int ComputeDelta(int src, int dst, int mapSize){ int increasing, decreasing; if (dst >= src) { increasing = dst - src; // 增加方向是直接的 decreasing = (mapSize + src) - dst; // 减少方向是环形的 } else { increasing = (mapSize + dst) - src; // 增加方向是环形的 decreasing = src - dst; // 减少方向是直接的 } if (increasing <= decreasing) { return increasing; } else { return -decreasing; }}public Position GetNextStepTowards(Position origin, Position target){ Position nextStep = new Position(0, 0); // 计算距离 int dx = ComputeDelta(origin.X, target.X, mapXSize); int dy = ComputeDelta(origin.Y, target.Y, mapYSize); // 保留主导距离,清除另一距离 // 如果它们相等,则保留两者 if (dx*dx > dy*dy) { dy = 0; } else if (dx*dx < dy*dy) { dx = 0; } // 标准化距离,使其为-1, 0, 或1 nextStep.X = dx.CompareTo(0); nextStep.Y = dy.CompareTo(0); return nextStep;}