public class Pathfinder : MonoBehaviour
{
[SerializeField] Vector2Int startCoordinates;
public Vector2Int StartCoordinates { get { return startCoordinates; } }
[SerializeField] Vector2Int endCoordinates;
public Vector2Int EndCoordinates { get { return endCoordinates; } }
Node startNode;
Node destinationNode;
Node currentSearchNode;
Dictionary<Vector2Int, Node> reached = new Dictionary<Vector2Int, Node>();
Queue<Node> frontier = new Queue<Node>();
[SerializeField] Vector2Int[] directions = { Vector2Int.up, Vector2Int.left, Vector2Int.down, Vector2Int.right }; // left, up, right, down
GridManager gridManager;
Dictionary<Vector2Int, Node> grid = new Dictionary<Vector2Int, Node>();
void Awake()
{
gridManager = FindObjectOfType<GridManager>();
if (gridManager != null)
{
grid = gridManager.Grid;
startNode = grid[startCoordinates];
destinationNode = grid[endCoordinates];
}
}
void Start()
{
GetNewPath();
}
public List<Node> GetNewPath(Vector2Int coordinates)
{
gridManager.ResetNodes();
BreadthFirstSearch(coordinates);
return BuildPath();
}
public List<Node> GetNewPath()
{
return GetNewPath(startCoordinates);
}
void ExploreNeighbors()
{
List<Node> neighbors = new List<Node>();
foreach (Vector2Int direction in directions)
{
Vector2Int neighborCoordinates = currentSearchNode.coordinates + direction;
if (grid.ContainsKey(neighborCoordinates))
{
neighbors.Add(grid[neighborCoordinates]);
}
}
foreach (Node neighbor in neighbors)
{
if(!reached.ContainsKey(neighbor.coordinates) && neighbor.isWalkable)
{
neighbor.connectedTo = currentSearchNode;
reached.Add(neighbor.coordinates, neighbor);
frontier.Enqueue(neighbor);
}
}
}
void BreadthFirstSearch(Vector2Int coordinates)
{
startNode.isWalkable = true;
destinationNode.isWalkable = true;
frontier.Clear();
reached.Clear();
bool isRunning = true;
frontier.Enqueue(grid[coordinates]);
reached.Add(coordinates, grid[coordinates]);
while (frontier.Count > 0 && isRunning)
{
currentSearchNode = frontier.Dequeue();
currentSearchNode.isExplored = true;
ExploreNeighbors();
if (currentSearchNode.coordinates == destinationNode.coordinates)
{
isRunning = false;
}
}
}
List<Node> BuildPath()
{
List<Node> pathToFind = new List<Node>();
Node currentNode = destinationNode;
pathToFind.Add(currentNode);
currentNode.isPath = true;
while (currentNode.connectedTo != null)
{
currentNode = currentNode.connectedTo;
pathToFind.Add(currentNode);
currentNode.isPath = true;
}
pathToFind.Reverse();
return pathToFind;
}
public bool WillBlockPath(Vector2Int coordinates)
{
if (grid.ContainsKey(coordinates))
{
bool previousState = grid[coordinates].isWalkable;
grid[coordinates].isWalkable = false;
List<Node> newPath = GetNewPath();
grid[coordinates].isWalkable = previousState;
if(newPath.Count <= 1)
{
GetNewPath();
return true;
}
}
return false;
}
public void NotifyReceivers(bool change)
{
BroadcastMessage("RecalculatePath", change , SendMessageOptions.DontRequireReceiver);
}
}
[RequireComponent(typeof(Enemy))]
public class EnemyMovements : MonoBehaviour
{
List<Node> path = new List<Node>();
[SerializeField][Range(0f, 5f)] float speed = 1f;
Enemy enemy;
EnemyHealth enemyHealth;
Pathfinder pathFinder;
GridManager gridManager;
float heightChange; //, healthSecOne, healthSecTwo, healthSecThree;
void OnEnable()
{
ReturnToStart();
RecalculatePath(true);
}
void Awake()
{
enemyHealth = GetComponent<EnemyHealth>();
enemy = GetComponent<Enemy>();
gridManager = FindObjectOfType<GridManager>();
pathFinder = FindObjectOfType<Pathfinder>();
heightChange = transform.position.y - 2.0f;
}
void RecalculatePath(bool resetPath)
{
Vector2Int coordinates;
if (resetPath)
{
coordinates = pathFinder.StartCoordinates;
}
else
{
coordinates = gridManager.GetCoordinatesFromPosition(transform.position);
}
StopAllCoroutines();
path.Clear();
path = pathFinder.GetNewPath(coordinates);
StartCoroutine(FollowRoute());
}
void ReturnToStart()
{
transform.position = gridManager.WorldPositionFromNodeCoordinates(pathFinder.StartCoordinates);
}
void HeightReduction()
{
float heightReduction = .15f;
int currentHitPoints = enemyHealth.CurrentHitPoints;
if (currentHitPoints < 9 && currentHitPoints > 0)
{
transform.Translate(Vector3.down * heightReduction);
}
}
void EndOfPathProcedure()
{
enemy.CashPenalty();
gameObject.SetActive(false);
}
IEnumerator FollowRoute()
{
for (int iterator = 1; iterator < path.Count; iterator++)
{
float initialTileX = transform.position.x;
float initialTileZ = transform.position.z;
Vector3 xZInitialPos = new Vector3(initialTileX, heightChange, initialTileZ);
//Vector3 initialTileTest = transform.position;
//Vector3 secondaryTile = gridManager.WorldSpaceFromVectors(path[iterator].coordinates);
float secondaryTileX = gridManager.WorldPositionFromNodeCoordinates(path[iterator].coordinates).x;
float secondaryTileZ = gridManager.WorldPositionFromNodeCoordinates(path[iterator].coordinates).z;
Vector3 xZdestinationPos = new Vector3(secondaryTileX, heightChange, secondaryTileZ);
float movementPercentage = 0f;
transform.LookAt(xZdestinationPos); //xZDesPos
while (movementPercentage < 1f)
{
movementPercentage += Time.deltaTime * speed;
transform.position = Vector3.Lerp(xZInitialPos, xZdestinationPos, movementPercentage);
yield return new WaitForEndOfFrame();
}
HeightReduction();
}
EndOfPathProcedure();
}
}
I must be doing something wrong, when I create a tower (whether it blocked the path or not) - my enemies slowdown or speed-up. Causing this merging between them.
I figure one of the two scripts provided is the culprit, but any hints in the right direction would be greatly appreciated.
Hi,
Have you already tried to add Debug.Logs to your code to see what is going on during runtime? Maybe the xZdestinationPos
value changed at some point or something else changed when you place a tower.
And have you already compared your code to the Lecture Project Changes which can be found in the Resources of this lecture?
I’ve tried adding Debug in a couple places, but nothing has been conclusive. I’m uncertain to the general location as to where the problem stems.
I had removed the XzDestinationPos section of code and replaced it with the original variables, and still had the issue unfortunately.
I’ve combed through the code for hours now though, I’m going to finish up the other aspects of the game and come back to it.
Where did you add Debug.Log? And what was the output in your Console?
In the PathFinder Script I had added Update and then Debug in Update and tried getting DestinationNode which didn’t return anything. Then I tried the endCoordinates, which didn’t return anything either.
Not sure if you can get information about Pure C# Classes.
I tried adding in the EnemyMovement Script in RecalculatePath method for the coordinates and in the FollowRoute Coroutine for the xZDesPos.
All returned nothing.
I’m uncertain how to use these tools properly.
Since EndCoordinates
and StartCoordinates
are value types, it is impossible that they do not return anything. Or did you mean that you do not get any messages in your Console?
Unity methods do not work in pure C# scripts. Also, Unity methods get called on active components only. “Active” in the context of Unity means: active in the scene. If the script component is attached to a prefab in the Assets folder, the Unity methods do not get called either.
I didn’t get any messages in the console sorry.
Ok, I will keep trying debugging until I get some useful information to provide
No message? You didn’t wrap the Debug.Logs in if-statements, did you? And other messages do appear, don’t they? If they don’t, maybe the messages are disabled in the Console window.
If other messages appear and if you did not wrap “your” Debug.Logs in if-statements, the methods don’t get called at runtime. That would explain the problem, and you’ll “just” have to figure out why the methods don’t get executed.