PathNodes are not taking correctly GCost/HCost/FCost. I need help!

Hello, I have finished the PathFinding Implementation block and the costs of each PathNode are not calculated correctly. I have even copied the code from gitlab and it still doesn’t work. I’m stuck!
!
error

It looks like ClearPathNodeInformation() has been run on all of the GridDebugObjects. Are you getting paths at this point?

Let’s take a look at your Pathfinding.cs, PathNode.cs, and PathfindingGridDebugObject scripts.

I have been trying different solutions and it still does not work correctly. How can I show you the code?

In the upper left hand corner of your keyboard, next to the 1 is a backwards apostrophe (`).
For each script, on it’s own line in the editor, type three of these backwards apostrophes, e.g.
```
and then paste in your script. Finally, at the end of the script, on it’s own line, type in the three backwards apostrophes again.
So with each script, it will look something like this:
```
public void InterestingCode()
{
//Dosomething (assume this is indented, without formatting, the editor strips whitespace)
}
```
becomes

public void InterestingCode()
{
   //DoSomething
}
public class PathFinding : MonoBehaviour
{

    private const int MOVE_STRAIGHT_COST = 10;
    private const int MOVE_DIAGONAL_COST = 14;
    [SerializeField] private Transform gridDebugGameObjectPrefab;
    //Variables para las celdas
    private int width;
    private int height;
    private int cellSize;
    //Varaible para almacenar el systema de grids que recibira en este caso objetos de tipo PathNode
    private GridSystem<PathNode> gridSystem;
    //Singleton de la clase
    public static PathFinding Instance { get; private set; }
 [SerializeField] private Transform gridDebugObjectPrefab;

   

    private void Awake()
    { 
        if (Instance != null)
        {
       
            Debug.LogError("There's more than one Pathfinding! " + transform + " - " + Instance);
            Destroy(gameObject);
            return;
        }
        Instance = this;

        gridSystem = new GridSystem<PathNode>(10, 10, 2f,
            (GridSystem<PathNode> g, GridPosition gridPosition) => new PathNode(gridPosition));
        gridSystem.CreateDebugObjects(gridDebugObjectPrefab);
    }

    public List<GridPosition> FindPath(GridPosition startGridPosition, GridPosition endGridPosition)
    {
        List<PathNode> openList = new List<PathNode>();
        List<PathNode> closedList = new List<PathNode>();

        PathNode startNode = gridSystem.GetGridObject(startGridPosition);
        PathNode endNode = gridSystem.GetGridObject(endGridPosition);
        openList.Add(startNode);

        for (int x = 0; x < gridSystem.GetWidth(); x++)
        {
            for (int z = 0; z < gridSystem.GetHeight(); z++)
            {
                GridPosition gridPosition = new GridPosition(x, z);
                PathNode pathNode = gridSystem.GetGridObject(gridPosition);

                pathNode.SetGCost(int.MaxValue);
                pathNode.SetHCost(0);
                pathNode.CalculateFCost();
                pathNode.ResetCameFromPathNode();
            }
        }

        startNode.SetGCost(0);
        startNode.SetHCost(CalculateDistance(startGridPosition, endGridPosition));
        startNode.CalculateFCost();

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

            if (currentNode == endNode)
            {
                // Reached final node
                return CalculatePath(endNode);
            }

            openList.Remove(currentNode);
            closedList.Add(currentNode);

            foreach (PathNode neighbourNode in GetNeighbourList(currentNode))
            {
                if (closedList.Contains(neighbourNode))
                {
                    continue;
                }

                int tentativeGCost =
                    currentNode.GetGCost() + CalculateDistance(currentNode.GetGridPosition(), neighbourNode.GetGridPosition());

                if (tentativeGCost < neighbourNode.GetGCost())
                {
                    neighbourNode.SetCameFromPathNode(currentNode);
                    neighbourNode.SetGCost(tentativeGCost);
                    neighbourNode.SetHCost(CalculateDistance(neighbourNode.GetGridPosition(), endGridPosition));
                    neighbourNode.CalculateFCost();

                    if (!openList.Contains(neighbourNode))
                    {
                        openList.Add(neighbourNode);
                    }
                }
            }
        }

        // No path found
        return null;
    }

    public int CalculateDistance(GridPosition gridPositionA, GridPosition gridPositionB)
    {
        GridPosition gridPositionDistance = gridPositionA - gridPositionB;
        int xDistance = Mathf.Abs(gridPositionDistance.x);
        int zDistance = Mathf.Abs(gridPositionDistance.z);
        int remaining = Mathf.Abs(xDistance - zDistance);
        return MOVE_DIAGONAL_COST * Mathf.Min(xDistance, zDistance) + MOVE_STRAIGHT_COST * remaining;
    }

    private PathNode GetLowestFCostPathNode(List<PathNode> pathNodeList)
    {
        PathNode lowestFCostPathNode = pathNodeList[0];
        for (int i = 0; i < pathNodeList.Count; i++)
        {
            if (pathNodeList[i].GetFCost() < lowestFCostPathNode.GetFCost())
            {
                lowestFCostPathNode = pathNodeList[i];
            }
        }
        return lowestFCostPathNode;
    }

    private PathNode GetNode(int x, int z)
    {
        return gridSystem.GetGridObject(new GridPosition(x, z));
    }

    private List<PathNode> GetNeighbourList(PathNode currentNode)
    {
        List<PathNode> neighbourList = new List<PathNode>();

        GridPosition gridPosition = currentNode.GetGridPosition();

        if (gridPosition.x - 1 >= 0)
        {
            // Left
            neighbourList.Add(GetNode(gridPosition.x - 1, gridPosition.z + 0));
            if (gridPosition.z - 1 >= 0)
            {
                // Left Down
                neighbourList.Add(GetNode(gridPosition.x - 1, gridPosition.z - 1));
            }

            if (gridPosition.z + 1 < gridSystem.GetHeight())
            {
                // Left Up
                neighbourList.Add(GetNode(gridPosition.x - 1, gridPosition.z + 1));
            }
        }

        if (gridPosition.x + 1 < gridSystem.GetWidth())
        {
            // Right
            neighbourList.Add(GetNode(gridPosition.x + 1, gridPosition.z + 0));
            if (gridPosition.z - 1 >= 0)
            {
                // Right Down
                neighbourList.Add(GetNode(gridPosition.x + 1, gridPosition.z - 1));
            }
            if (gridPosition.z + 1 < gridSystem.GetHeight())
            {
                // Right Up
                neighbourList.Add(GetNode(gridPosition.x + 1, gridPosition.z + 1));
            }
        }

        if (gridPosition.z - 1 >= 0)
        {
            // Down
            neighbourList.Add(GetNode(gridPosition.x + 0, gridPosition.z - 1));
        }
        if (gridPosition.z + 1 < gridSystem.GetHeight())
        {
            // Up
            neighbourList.Add(GetNode(gridPosition.x + 0, gridPosition.z + 1));
        }

        return neighbourList;
    }

    private List<GridPosition> CalculatePath(PathNode endNode)
    {
        List<PathNode> pathNodeList = new List<PathNode>();
        pathNodeList.Add(endNode);
        PathNode currentNode = endNode;
        while (currentNode.GetCameFromPathNode() != null)
        {
            pathNodeList.Add(currentNode.GetCameFromPathNode());
            currentNode = currentNode.GetCameFromPathNode();
        }

        pathNodeList.Reverse();

        List<GridPosition> gridPositionList = new List<GridPosition>();
        foreach (PathNode pathNode in pathNodeList)
        {
            gridPositionList.Add(pathNode.GetGridPosition());
        }

        return gridPositionList;
    }

}

public class PathNode : MonoBehaviour
{
    private GridPosition gridPosition;
    //Variable para almacenar el valor de moverse en una dirección a la celda contigua
    private int gCost;
    //Valor para almacenar el valor de los costes hacia el punto de destio
    private int hCost;
    //Variable para almacenar la suma de gCosta más hCosta
    private int fCost;
    //Variable para almacenar la referencia el PathNode anterior/del que venimos
    private PathNode cameFromPathNode;
    //Construcctor simple que solo recibe la posición del grid para situarlo
    public PathNode(GridPosition gridPosition)
    {
        this.gridPosition = gridPosition;
    }
ublic override string ToString()
    {
        return gridPosition.ToString();
    }

    public int GetGCost()
    {
        return gCost;
    }

    public int GetHCost()
    {
        return hCost;
    }

    public int GetFCost()
    {
        return fCost;
    }

    public void SetGCost(int gCost)
    {
        this.gCost = gCost;
    }

    public void SetHCost(int hCost)
    {
        this.hCost = hCost;
    }

    public void CalculateFCost()
    {
        this.fCost = gCost + hCost;
    }

    public void ResetCameFromPathNode()
    {
        cameFromPathNode = null;
    }

    public void SetCameFromPathNode(PathNode pathNode)
    {
        cameFromPathNode = pathNode;
    }

    public PathNode GetCameFromPathNode()
    {
        return cameFromPathNode;
    }

    public GridPosition GetGridPosition()
    {
        return gridPosition;
    }

}

public class PathFindingGridDebugObject : GridDebugObject
{
    //Variables para los Textos de los nodos. Es TextMeshPro porque los texto no están en un Canvas
    [SerializeField] private TextMeshPro gCostText;
    [SerializeField] private TextMeshPro hCostText;
    [SerializeField] private TextMeshPro fCostText;
    //Variable para almacenar el PathNode que toque
    private PathNode pathNode;
    public override void SetGridObject(object gridObject)
    { 
        //Esta línea quiere decir que se ejecuta el SetGridObject de la clase de la que extiendad, la original
        base.SetGridObject(gridObject);
        //Como gridObject es un objeto genérico le hago un cast a PathNode
        pathNode = (PathNode)gridObject;
       
    }
    protected override void Update()
    {
        base.Update();
        gCostText.text = pathNode.GetGCost().ToString();
        hCostText.text = pathNode.GetHCost().ToString();
        fCostText.text = pathNode.GetFCost().ToString();
    }

}

These look right, so far.

It looks from the picture like the StartNode is correctly updating but other nodes are not, which indicates that it may not be getting the neighbornodes.
Let’s add a Debug to see what we’re getting for neighbors:
In GetNeighborList(), just before the return statement, add the following:

StringBuilder builder = new();
builder.Append($"GetNeighborList({gridPosition}) = ");
foreach(var  node in neighborList)
{
    builder.Append($"{node.GetGridPosition()} ");
}
Debug.Log(builder.ToString());

Hello!

First of all thank you very much for your help.
I have implemented the changes that you have proposed to me in the code and for the moment it does not show anything conclusive.

    private List<PathNode> GetNeighbourList(PathNode currentNode)
    {
        List<PathNode> neighborList = new List<PathNode>();

        GridPosition gridPosition = currentNode.GetGridPosition();

        if (gridPosition.x - 1 >= 0)
        {
            // Left
            neighborList.Add(GetNode(gridPosition.x - 1, gridPosition.z + 0));
            if (gridPosition.z - 1 >= 0)
            {
                // Left Down
                neighborList.Add(GetNode(gridPosition.x - 1, gridPosition.z - 1));
            }

            if (gridPosition.z + 1 < gridSystem.GetHeight())
            {
                // Left Up
                neighborList.Add(GetNode(gridPosition.x - 1, gridPosition.z + 1));
            }
        }

        if (gridPosition.x + 1 < gridSystem.GetWidth())
        {
            // Right
            neighborList.Add(GetNode(gridPosition.x + 1, gridPosition.z + 0));
            if (gridPosition.z - 1 >= 0)
            {
                // Right Down
                neighborList.Add(GetNode(gridPosition.x + 1, gridPosition.z - 1));
            }
            if (gridPosition.z + 1 < gridSystem.GetHeight())
            {
                // Right Up
                neighborList.Add(GetNode(gridPosition.x + 1, gridPosition.z + 1));
            }
        }

        if (gridPosition.z - 1 >= 0)
        {
            // Down
            neighborList.Add(GetNode(gridPosition.x + 0, gridPosition.z - 1));
        }
        if (gridPosition.z + 1 < gridSystem.GetHeight())
        {
            // Up
            neighborList.Add(GetNode(gridPosition.x + 0, gridPosition.z + 1));
        }

        StringBuilder builder = new();
        builder.Append($"GetNeighborList({gridPosition}) = ");
        foreach (var node in neighborList)
        {
            builder.Append($"{node.GetGridPosition()} ");
        }
        Debug.Log(builder.ToString());

        return neighborList;
    }

Actually, the screenshot with the console tells me exactly what’s wrong. Easy to miss on the first pass through the code:
The message is telling you that you are trying to create a new object that is inherited from MonoBehaviour. In this case, it’s Pathnode.
The header should simply read

public class PathNode
{

THAT WAS! Thank u so much, what a “dumb” mistake!!

Happens all the time, and easy to miss. Whenever you create a new script, Unity generously creates a boilerplate MonoBehaviour script for you.

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms