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!
!
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.
- Forum User Guides : How to apply code formatting within your post
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.