Pathfinding Script That Labels Paths Correctly

The original version just has the one path marked on the nodes, but what about when the enemies split off into different paths? I made it so that the nodes being followed by any enemy are marked. The nodes are also unmarked when they are not in use anymore. I also made it so that a new path isn’t found by the enemies when it would be unnecessary to do so.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[RequireComponent(typeof(Enemy))]
public class EnemyMover : MonoBehaviour
{
    [SerializeField] [Range(0f, 5f)] private float speed = 1f;
    static List<EnemyMover> enemies = new List<EnemyMover>();
    static int num;

    public List<Node> hypotheticalPath;
    public List<Node> removePath = new List<Node>();
    private List<Node> path = new List<Node>();
    private Enemy enemy;
    private GridManager gridManager;
    private PathFinder pathFinder;

    private void OnEnable()
    {
        ReturnToStart();
        RecalculatePath(true);
    }

    private void Awake()
    {
        num += 1;
        gameObject.name = "Ram: " + num;
        enemy = GetComponent<Enemy>();
        gridManager = FindObjectOfType<GridManager>();
        pathFinder = FindObjectOfType<PathFinder>();
        enemies.Add(this);
    }

    void RecalculatePath(bool resetPath)
    {
        Vector2Int coordinates = new Vector2Int();

        if (resetPath)
        {
            coordinates = pathFinder.StartCoordinates;
        }
        else
        {
            coordinates = gridManager.GetCoordinatesFromPosition(transform.localPosition);
        }
        
        if (WillAlterPath()) // Checks if the the placed tower will result in a new path
        {
            CheckIfPathNeedsDeleted();
            StopAllCoroutines();
            path.Clear();
            path = pathFinder.GetNewPath(coordinates);

            StartCoroutine(FollowPath());
        }
        else 
        {
            if (transform.localPosition == gridManager.GetPositionFromCoordinates(pathFinder.StartCoordinates)) // If a new path is not needed then keep following the current path
            {
                StartCoroutine(FollowPath());
            }
        }
    }

    bool WillAlterPath() // Checks if a new path is needed
    {
        hypotheticalPath = new List<Node>(); 

        hypotheticalPath = pathFinder.GetNewPath(); // path is created to see if it's different from the current path

        if (hypotheticalPath.Count != path.Count)
        {
            return true;
        }
        else
        {
            foreach (Node node in hypotheticalPath)
            {
                if (!path.Contains(node))
                {
                    return true;
                }       
            }
        }
        return false;
    }

        void ReturnToStart()
        {
            transform.localPosition = gridManager.GetPositionFromCoordinates(pathFinder.StartCoordinates);
        }

        bool DoEnemiesUseNode(Node node) // Checks if enemies are using this node in their pathfinding
        {
            foreach (EnemyMover enemyPath in enemies)
            {
                if (enemyPath.path.Contains(node))
                { 
                    return true;
                }  
            }

            return false;
        }

        bool DeletePath() // Checks if any nodes need to be unmarked as a path
        {
            removePath = new List<Node>(); // List of nodes that will be unmarked as a path

            foreach (KeyValuePair<Vector2Int, Node> node in gridManager.Grid) // Goes through each node in the grid
            {
                if (node.Value.isPath) // Only includes the nodes that are marked as a path
                {
                    if (DoEnemiesUseNode(node.Value) == false) // If enemies are not using this node in their pathfinding
                    {
                        removePath.Add(node.Value); 
                    }
                }
            }

            if (removePath.Count > 0) // If there were any nodes to be removed as a path then return true
            {
                return true;
            }

            return false;
        }

        void CheckIfPathNeedsDeleted()
        {
            if (DeletePath())
            {
                foreach (Node node in removePath) // Unmark isPath in each node in removePath
                {
                   node.isPath = false;
                }
            }
    }

        void FinishPath()
        {
            CheckIfPathNeedsDeleted();
            enemy.StealGold();
            gameObject.SetActive(false);
        }

        IEnumerator FollowPath()
        {
            for (int i = 1; i < path.Count; i++)
            {
                Vector3 startPosition = transform.localPosition;
                Vector3 endPosition = gridManager.GetPositionFromCoordinates(path[i].coordinates);
                float travelPercent = 0f;

                transform.LookAt(endPosition + new Vector3(5, 0, 5));

                while (travelPercent < 1)
                {
                    travelPercent += speed * Time.deltaTime;
                    transform.localPosition = Vector3.Lerp(startPosition, endPosition, travelPercent);

                    yield return new WaitForEndOfFrame();
                }
            }

            FinishPath();
        }
    
}

1 Like

Very good job!

Privacy & Terms