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