My Move Action got broken by the pathLength check in MoveAction.cs

Hello! I’m a beginner game developer and have been taking this course. I’ve encountered an issue with my move action. The problem appears when I include a path length check in my MoveAction.cs script. I’ve checked the code so many times and even tried copying the classes from GitLab, but the problem still persists.

If I remove the path length check from the code the move action works. so if I remove this block:

if (!Pathfinding.Instance.HasPath(unitGridPosition, testGridPosition, out int pathLength)) {
         continue;
}

int pathFindingDistanceMultiplier = 10;
if (pathLength > (maxMoveDistance * pathFindingDistanceMultiplier)) {
         continue;
}

To explain: I’ve made an “out” parameter from the hasPath() method to get the pathLength variable here instead of calling FindPath twice. I did that because the game got laggy, and I thought that might be the reason.

Here’s my HasPath() method in PathFinding.cs:

public bool HasPath(GridPosition startGridPosition, GridPosition endGridPosition, out int pathL) {
        bool hasPath = FindPath(startGridPosition, endGridPosition, out int pathLength) != null;
        pathL = pathLength;
        return hasPath;
    }

and the FindPath() method:

public List<GridPosition> FindPath(GridPosition startGridPosition, GridPosition endGridPosition, out int pathLength)
    {
        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.ResetPredecessorPathNode();
            }
        }

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

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

            if (currentNode == endNode)
            {
                pathLength = endNode.GetFCost();
                return CalculatePath(endNode);
            }

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

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

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

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

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

        pathLength = 0;
        return null;
    }

What’s the problem? Everything looks fine so without knowing what the issue is it’s difficult to pinpoint a possible cause

Well, basically the Grid Visual is not showing at all and also I can’t move the Unit to any position.
An exception to this is when I try to position the Unit at some positions, like in the pictures, I can move to those positions that the visual is on… I have no clue what’s going on…



It looks like the problem may be elsewhere. Your code is fine, so perhaps there’s a mistake somewhere else in the pathfinding. Please paste the full Pathfinding.cs so we can take a look

Sure, I don’t think it’s going to be in the Pathfinding script since I’ve tried copying the whole class from GitLab, like I mentioned in my first comment. But here’s how it looks now, with my code:

public class Pathfinding : MonoBehaviour
{
    private const int MOVE_STRAIGHT_COST = 10;
    private const int MOVE_DIAGONAL_COST = 14;

    [SerializeField] private Transform gridDebugObjectPrefab;
    [SerializeField] private LayerMask obstaclesLayerMask;

    public static Pathfinding Instance { get; private set; }

    private int width;
    private int height;
    private float cellSize;
    private GridSystem<PathNode> gridSystem;

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

    public void Setup(int width, int height, float cellSize) {
        this.width = width;
        this.height = height;
        this.cellSize = cellSize;

        gridSystem = new GridSystem<PathNode>(width, height, cellSize,
            (GridSystem<PathNode> g, GridPosition gridPosition) => new PathNode(gridPosition));
        //gridSystem.CreateDebugObjects(gridDebugObjectPrefab);

        for (int x = 0; x < width; x++) {
            for (int z = 0; z < height; z++) {
                GridPosition gridPosition = new GridPosition(x, z);
                Vector3 worldPosition = LevelGrid.Instance.GetWorldPosition(gridPosition);
                float rayCastOffsetDistance = 5f;
                if(Physics.Raycast(
                    worldPosition + Vector3.down * rayCastOffsetDistance,
                    Vector3.up, rayCastOffsetDistance * 2,
                    obstaclesLayerMask)) {
                    // There is obstacle on this position
                    GetNode(x, z).SetIsWalkable(false);
                }
            }
        }
    }
    
    public List<GridPosition> FindPath(GridPosition startGridPosition, GridPosition endGridPosition, out int pathLength)
    {
        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.ResetPredecessorPathNode();
            }
        }

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

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

            if (currentNode == endNode)
            {
                pathLength = endNode.GetFCost();
                return CalculatePath(endNode);
            }

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

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

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

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

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

        pathLength = 0;
        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)
    {
        Debug.Log(x + " " + 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.GetPredecessorPathNode() != null)
        {
            pathNodeList.Add(currentNode.GetPredecessorPathNode());
            currentNode = currentNode.GetPredecessorPathNode();
        }

        pathNodeList.Reverse();

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

        return gridPositionList;
    }

    public bool IsWalkableGridPosition(GridPosition gridPosition) {
        return gridSystem.GetGridObject(gridPosition).IsWalkable();
    }

    public bool HasPath(GridPosition startGridPosition, GridPosition endGridPosition, out int pathL) {
        bool hasPath = FindPath(startGridPosition, endGridPosition, out int pathLength) != null;
        pathL = pathLength;
        return hasPath;
    }
}

Here are the fields set in the editor:

And if needed, here’s the PathNode script as well:

public class PathNode
{
    private GridPosition gridPosition;
    private int gCost;
    private int hCost;
    private int fCost;
    private bool isWalkable = true;

    private PathNode predecessorPathNode;
    public PathNode(GridPosition gridPosition) {
        this.gridPosition = gridPosition;
    }

    public PathNode GetPredecessorPathNode() {
        return predecessorPathNode;
    }
    
    public void SetPredecessorPathNode(PathNode predecessorPathNode) {
        this.predecessorPathNode = predecessorPathNode;
    }

    public void ResetPredecessorPathNode() {
        this.predecessorPathNode = null;
    }

    public override string ToString() {
        return gridPosition.ToString();
    }

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

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

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

    public int GetGCost() {
        return gCost;
    }

    public int GetHCost() {
        return hCost;
    }

    public int GetFCost() {
        return fCost;
    }

    public GridPosition GetGridPosition() {
        return gridPosition;
    }

    public void SetIsWalkable(bool isWalkable) {
        this.isWalkable = isWalkable;
    }

    public bool IsWalkable() {
        return isWalkable;
    }
}

Yup, it’s all good. Would it be possible to upload the project somewhere so I can take a look? It would be easier than trying to find the issue in posts

1 Like

Of course! Here’s the link:

OK, Sorry it took so long. Your issue is in GridPosition.cs. You have a mistake in the operator override

public static GridPosition operator -(GridPosition a, GridPosition b) {
    return new GridPosition(a.x - b.x, a.z + b.z);
}

it should be

public static GridPosition operator -(GridPosition a, GridPosition b) {
    return new GridPosition(a.x - b.x, a.z - b.z);
}
3 Likes

Yes, that did it! Thank you very much, I’m disappointed by the fact that I didn’t spot that issue… Everything works now! :pray: :pray:

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

Privacy & Terms