实时游戏的网格寻路

问题描述

我正在为诸如《帝国时代》之类的游戏进行统一的寻路(我需要这些单位在4个方向上移动,而不是在它们之间堆叠并包围目标) 我的问题如下:如果一个单元被包围并且我将它们指定为目标,我希望这些单元分组关闭。目前,如果目标部队被包围,则所有其他试图到达目标的部队都会发疯。

public void Findpath(Vector3 startPosition,Vector3 targetDestination)
{
    Node StartNode = NodeFromWorldPoint(startPosition);
    Node TargetNode = NodeFromWorldPoint(targetDestination);

    List<Node> OpenList = new List<Node>();
    HashSet<Node> ClosedList = new HashSet<Node>();

    OpenList.Add(StartNode);

    while (OpenList.Count > 0)
    {
        Node CurrentNode = OpenList[0];
        for (int i = 1; i < OpenList.Count; i++)
        {
            if (OpenList[i].FCost < CurrentNode.FCost || OpenList[i].FCost == CurrentNode.FCost && OpenList[i].hCost < CurrentNode.hCost)
            {
                CurrentNode = OpenList[i];
            }
        }
        OpenList.Remove(CurrentNode);
        ClosedList.Add(CurrentNode);

        if (CurrentNode == TargetNode)
        {
            GetFinalPath(StartNode,TargetNode);
        }

        foreach (Node NeighborNode in CurrentNode.neighbors)
        {
            if (NeighborNode.blocked || ClosedList.Contains(NeighborNode) || NeighborNode.occupied)
            {
                continue;
            }
            int MoveCost = CurrentNode.gCost + Manhattendistance(CurrentNode,NeighborNode);

            if (MoveCost < NeighborNode.gCost || !OpenList.Contains(NeighborNode))
            {
                NeighborNode.gCost = MoveCost;
                NeighborNode.hCost = Manhattendistance(NeighborNode,TargetNode);
                NeighborNode.parentNode = CurrentNode;

                if (!OpenList.Contains(NeighborNode))
                {
                    OpenList.Add(NeighborNode);
                }
            }
        }
    }
}

void GetFinalPath(Node startingNode,Node endNode)
{
    List<Node> FinalPath = new List<Node>();
    Node CurrentNode = endNode;

    while (CurrentNode != startingNode)
    {
        FinalPath.Add(CurrentNode);
        CurrentNode = CurrentNode.parentNode;
    }

    FinalPath.Reverse();

    finalPath = FinalPath;
}

int Manhattendistance(Node nodeA,Node nodeB)
{
    int dist = (int)Vector3.distance(nodeA.transform.position,nodeB.transform.position);

    return dist;
}

public Node NodeFromWorldPoint(Vector3 worldPosition)
{
    var nod = Physics2D.OverlapCircleAll(worldPosition,10);
    var nodos = new List<Node>();
    foreach (var item in nod)
    {
        if (item.GetComponent<Node>())
            nodos.Add(item.GetComponent<Node>());
    }

    float dist = Mathf.Infinity;
    Node closest = null;
    foreach (var item in nodos)
    {
        var ds = Vector3.distance(worldPosition,item.transform.position);
        if (ds < dist)
        {
            dist = ds;
            closest = item;
        }
    }
    return closest;
}

解决方法

前言:我还没有玩过《帝国时代》,所以我不是100%知道我要重现哪种动作(发布视频会有所帮助),但是如果我正确理解了,您会重新寻找像运动的棋盘(没有对角线)。 [编辑] OP提供了可视链接供参考,就像棋盘一样的运动。

您似乎正在尝试实现A *。看看您发布的示例,我发现了一些可能会导致您出现问题的地方。

  1. 初始化节点

运行搜索后,您是否要初始化/重置节点?我在示例中看不到您要执行的操作,因此,除非您在另一段代码中执行此操作,否则在多次运行搜索时可能会使用旧的成本值。

  1. 可允许的启发式(曼哈顿距离)

假设您正在尝试实现A *,算法的关键部分是您的启发式算法是可以接受的,这意味着它不会低估成本。您调用了启发式函数Manhattan Distance,但是您的实现实际上是欧几里得距离(请参见区别here)。如果您的单位只能沿四个方向(即上,下,左,右)移动,而不能沿八个方向移动,那么这可能就是您的搜索无法正常工作的原因。

请注意,如果您可以发布有关该行为的视频或更具描述性,那么“发疯”会有所帮助。 [EDIT] OP提供了一个视频来演示行为。

[更新]

如果您尝试获得的行为是尽可能接近,我会考虑实施某种逻辑来确定何时“包围”某个单元,然后通过某种算法(贪婪的方法可能还可以)选择一个最近的节点作为目标。

因此,如果状态看起来像这样:

X X X
X O X
X X X

在X是红色单位而O是蓝色单位的情况下,新的红色单位将包围蓝色单位的下一个“目标”节点看起来像:

T T T T T
T X X X T
T X O X T
T X X X T
T T T T T

T是可能的目标节点

,

感谢您的回复。 我没有正确重置节点,所以我解决了这个问题。但是问题依然存在。 这就是我要寻找的动作:(47分钟左右)

https://www.youtube.com/watch?v=TPM0Kn_IS-U

我希望他们不要共享相同的网格空间,但是我希望他们对目标进行加密,并且如果目标附近没有空间,则他们将保持尽可能近的距离。

https://www.youtube.com/watch?v=h7iUghtIoCQ&feature=youtu.be

您可以看到,如果已经有人在里面,他们就不能去另一个部门。如果他们想输入相同的扇区,则需要等待一小段时间并重新计算路径。当所有空间都被占用并且他们找不到通往目标的道路时,问题就开始了,他们开始回头跳舞直到找到空间。我希望,如果没有办法实现其目标,它们至少应保持尽可能近的距离。

再次感谢!英语不是我的主要语言,对不起,如果我不太清楚