Iann7
Iann7

Reputation: 79

A* pathfinding algorithm INFINITE WHILE LOOP (c#)(unity)

I'm trying to come up with my "own" a* pathfinding algorithm following the explanation of this article : https://www.redblobgames.com/pathfinding/a-star/introduction.html

But it seems that my pathfinding code runs into some sort of infinte-while-loop which inmediatly crashes Unity. But I honestly do not know what am I doing wrong

Here's my code

EDIT : it seems that unity editor crashes due to an OutOfMemory exception. I do not know what is going on public class 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;
    }
}

Upvotes: 1

Views: 357

Answers (2)

OniiChanFL
OniiChanFL

Reputation: 51

I found two more things.

First your getNode function shouldn't look like this:

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

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

It should be:

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

And the Second thing is for your getNeighbors. I do not know exactly how you create the Nodes, but for example they are in a Grid you should check if there is something for X and Y and not OutOfIndex. Here my check out of my Code for one NeighborNode:

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

Because of getNode function you add to the openList NULL

Upvotes: 0

OniiChanFL
OniiChanFL

Reputation: 51

I tried to check your Code with my and 2 Ideas you could try.

First is I think you shouldn't set the in the foreach the newCost before the if. So you could try:

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);

    }
}

   

Or one more thing. I have for some Reasons again a openList.Contains check before I add it to the openList. I do not know why again I did this but I think maybe you can try it, don't know if this helps. I made it quite a long time ago:

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);
        }
    }
}

Upvotes: 1

Related Questions