【问题标题】:A* pathfinding algorithm INFINITE WHILE LOOP (c#)(unity)A* 寻路算法 INFINITE WHILE LOOP (c#)(unity)
【发布时间】:2020-07-19 02:14:42
【问题描述】:

我正在尝试按照本文的解释提出我的“自己的”a* 寻路算法:https://www.redblobgames.com/pathfinding/a-star/introduction.html

但我的寻路代码似乎遇到了某种无限循环,这会立即使 Unity 崩溃。但老实说我不知道​​我做错了什么

这是我的代码

编辑:似乎统一编辑器由于 OutOfMemory 异常而崩溃。我不知道发生了什么事 公共类 PathFinding {

    List<PathNode> openList;
    List<PathNode> closedList;
    Grid_Ian<PathNode> grid;
 
   
    public PathFinding(Grid_Ian<PathNode> grid)
    {
        openList = new List<PathNode>();
        closedList = new List<PathNode>();
        this.grid = grid;
    }

    public List<PathNode> makePath(PathNode startNode, PathNode endNode)
    {

        if (startNode == null || endNode == null)
         {
             return new List<PathNode>();
         } 
         if(grid.getGridObject(startNode.x,startNode.y) == null
             || grid.getGridObject(endNode.x, endNode.y) == null)
         {
             return new List<PathNode>();
         }

         startNode.hCost = calculateDistanceCost(startNode, endNode);
         startNode.gCost = 0;
         startNode.calculateFCost();
         startNode.cameFrom = null;

         openList.Add(startNode);
         PathNode currentNode = startNode;
         while (openList.Count > 0)
         {


            Debug.Log("LOOPING");
            currentNode = getLowestFcost(openList);
            openList.Remove(currentNode);
            closedList.Add(currentNode);

            if (currentNode.x == endNode.x &&
                currentNode.y == endNode.y)
             {
                 return getPath(currentNode);

             }

            foreach (PathNode next in getNeighbors(currentNode))
            {
                int newCost = currentNode.fCost + calculateDistanceCost(currentNode, next);
                if (closedList.Contains(next)) continue;
                if (next.cameFrom == null || newCost < next.fCost)
                {
                    Debug.Log("NUEVO VECINO");
                    int nextCost = calculateDistanceCost(currentNode, next);
                    next.gCost = currentNode.gCost + nextCost;
                    next.hCost = currentNode.hCost + nextCost;
                    next.calculateFCost();
                    next.cameFrom = currentNode;
                    openList.Add(next);

                }
            }
             
         }
         return new List<PathNode>();
       
     
       
    }

    public List<PathNode> getNeighbors(PathNode currentNode)
    {
        List<PathNode> neighborNodes = new List<PathNode>();
        if (currentNode.x - 1 >= 0)
        {
            //left
            neighborNodes.Add(getNode(currentNode.x - 1, currentNode.y));
        }

        if (currentNode.x + 1 >= 0)
        {
            //right
            neighborNodes.Add(getNode(currentNode.x + 1, currentNode.y));
        }
        //up
        if (currentNode.y + 1 >= 0)
        {
            neighborNodes.Add(getNode(currentNode.x, currentNode.y + 1));
        }
        //down
        if (currentNode.y - 1 >= 0)
        {
            neighborNodes.Add(getNode(currentNode.x, currentNode.y - 1));
        }
        return neighborNodes;
    }

    public PathNode getNode(int x, int y)
    {
        if(grid.getGridObject(x,y) == null)
        {

        }
        return grid.getGridObject(x, y);
    }

    private PathNode getLowestFcost(List<PathNode> nodeList)
    {
        PathNode lowestNode = getNode(0,0); // TODO : ARREGLAR
        int fCost = 0;
        foreach (PathNode node in nodeList)
        {
            if (fCost > node.fCost)
            {
                fCost = node.fCost;
                lowestNode = node;
            }
        }
        return lowestNode;
    }

    private int calculateDistanceCost(PathNode a, PathNode b)
    {

        return Mathf.Abs(a.x - b.x) + Mathf.Abs(a.y - b.y);
    }

    private List<PathNode> getPath(PathNode currentNode ){
        List<PathNode> path = new List<PathNode>();
        path.Add(currentNode);
        while (currentNode.cameFrom != null)
        {
            currentNode = currentNode.cameFrom;
            path.Add(currentNode);
            
        }
        path.Reverse();
        return path;
    }

    public void getXY(Vector3 worldPosition, out int x, out int y)
    {
        grid.GetXY(worldPosition, out x, out y);
    }

}

public class PathNode {
    public int x, y;
    public int hCost, gCost,fCost;
    public PathNode cameFrom;
   // G = start
   // H = end
   // F = G + H 

    public PathNode(int x,int y)
    {
        this.x = x;
        this.y = y;
        
    }

    public void calculateFCost()
    {
        fCost = hCost + gCost;
    }
}

【问题讨论】:

  • 哪里崩溃了?
  • @EtiennedeMartel 似乎它在 while 循环内崩溃了,但老实说我不知道​​,因为统一崩溃了。
  • 等等,编辑器崩溃了?
  • @EtiennedeMartel 是的!
  • 托管代码不应使 Unity 崩溃,除非编辑器中存在错误。尝试更新。

标签: c# unity3d


【解决方案1】:

我尝试使用我的和您可以尝试的 2 个想法来检查您的代码。

首先我认为你不应该在 if 之前在 foreach 中设置 newCost。所以你可以试试:

foreach (PathNode next in getNeighbors(currentNode))
{
    
    if (closedList.Contains(next)) continue;
    
    int newCost = currentNode.fCost + calculateDistanceCost(currentNode, next);
    
    if (next.cameFrom == null || newCost < next.fCost)
    {
        Debug.Log("NUEVO VECINO");
        int nextCost = calculateDistanceCost(currentNode, next);
        next.gCost = currentNode.gCost + nextCost;
        next.hCost = currentNode.hCost + nextCost;
        next.calculateFCost();
        next.cameFrom = currentNode;
        openList.Add(next);

    }
}

   

或者还有一件事。由于某些原因,在将其添加到 openList 之前,我再次进行了 openList.Contains 检查。我不知道为什么我又这样做了,但我想也许你可以试试,不知道这是否有帮助。我很久以前就做到了:

foreach (PathNode next in getNeighbors(currentNode))
{
    int newCost = currentNode.fCost + calculateDistanceCost(currentNode, next);
    if (closedList.Contains(next)) continue;
    if (next.cameFrom == null || newCost < next.fCost)
    {
        Debug.Log("NUEVO VECINO");
        int nextCost = calculateDistanceCost(currentNode, next);
        next.gCost = currentNode.gCost + nextCost;
        next.hCost = currentNode.hCost + nextCost;
        next.calculateFCost();
        next.cameFrom = currentNode;
        
        if(!openList.Contains(next))
        {
                openList.Add(next);
        }
    }
}

【讨论】:

  • 嗨!我实际上已经实现了您的建议,但我的代码中似乎还有另一个错误,因为统一不断崩溃:(。感谢您的回答!
【解决方案2】:

我又发现了两件事。

首先,您的 getNode 函数不应如下所示:

public PathNode getNode(int x, int y)
{
    if(grid.getGridObject(x,y) == null)
    {

    }
    return grid.getGridObject(x, y);
}

应该是:

public PathNode getNode(int x, int y)
{
    if(grid.getGridObject(x,y) != null)
    {
        return grid.getGridObject(x, y);
    }
    return null; //need error handling
}

第二件事是为你的 getNeighbors 做的。我不知道你是如何创建节点的,但是例如它们在一个网格中,你应该检查是否有 X 和 Y 的东西,而不是 OutOfIndex。 在这里,我检查了一个 NeighborNode 的代码:

if (checkX >= 0 && checkX < gridSizeX)
{
    if (checkY >= 0 && checkY < gridSizeY)
    {
        neighborList.Add(nodeArray[checkX, checkY]);
    }
}

因为 getNode 函数你添加到 openList NULL

【讨论】:

  • 单独的答案应该分开。如果这个答案本身不能回答问题,应该是added to the other answer as an edit
  • "应该是:" 并且它遵循一个无法编译的代码。你不能声明一个函数,说它返回一个对象,而不是返回它。如果grid.getGridObject(x,y) == null 函数不返回任何内容。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-15
  • 2011-05-08
  • 1970-01-01
  • 1970-01-01
  • 2012-03-19
相关资源
最近更新 更多