This is the pathfinding:
public class Pathfinding : MonoBehaviour
{
public static Pathfinding Instance { get; private set; }
private const int MOVE_STRAIGHT_COST = 10;
private const int MOVE_DIAGONAL_COST = 14;
[SerializeField]
private Transform gridDebugObjectPrefab;
[SerializeField]
private LayerMask obstaclesLayerMask;
[SerializeField]
private LayerMask floorLayerMask;
private int width;
private int height;
private float cellSize;
private int floorAmount;
private List<GridSystem<PathNode>> gridSystemList;
private void Awake()
{
if (Instance != null)
{
Debug.Log($"Multiple Pathfinding at {transform} - {Instance}");
Destroy(gameObject);
return;
}
Instance = this;
}
public void Setup(int width, int height, float cellSize, int floorAmount)
{
this.width = width;
this.height = height;
this.cellSize = cellSize;
this.floorAmount = floorAmount;
gridSystemList = new List<GridSystem<PathNode>>();
for (int floor = 0; floor < floorAmount; floor++)
{
GridSystem<PathNode> gridSystem = new GridSystem<PathNode>(width, height, cellSize, floor, LevelGrid.FLOOR_HEIGHT,
(GridSystem<PathNode> g, GridPosition gridPosition) => new PathNode(gridPosition));
//gridSystem.CreateDebugObjects(gridDebugObjectPrefab);
gridSystemList.Add(gridSystem);
}
for (int x = 0; x < width; x++)
{
for (int z = 0; z < height; z++)
{
for (int floor = 0; floor < floorAmount; floor++)
{
GridPosition gridPosition = new GridPosition(x, z, floor);
Vector3 worldPosition = LevelGrid.Instance.GetWorldPosition(gridPosition);
float raycastOffsetDistance = 1f;
GetNode(x, z, floor).SetIsWalkable(false);
if (Physics.Raycast(
worldPosition + Vector3.up * raycastOffsetDistance,
Vector3.down, raycastOffsetDistance * 2,
floorLayerMask))
{
GetNode(x, z, floor).SetIsWalkable(true);
}
if (Physics.Raycast(
worldPosition + Vector3.down * raycastOffsetDistance,
Vector3.up, raycastOffsetDistance * 2,
obstaclesLayerMask))
{
GetNode(x, z, floor).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 = GetGridSystem(startGridPosition.floor).GetGridObject(startGridPosition);
PathNode endNode = GetGridSystem(endGridPosition.floor).GetGridObject(endGridPosition);
openList.Add(startNode);
for (int x = 0; x < width; x++)
{
for (int z = 0; z < height; z++)
{
for (int floor = 0; floor < floorAmount; floor++)
{
GridPosition gridPosition = new GridPosition(x, z, floor);
PathNode pathNode = GetGridSystem(floor).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 last node
pathLength = endNode.GetFCost();
return CalculatePath(endNode);
}
openList.Remove(currentNode);
closedList.Add(currentNode);
foreach (PathNode neighborNode in GetNeighborList(currentNode))
{
if (closedList.Contains(neighborNode))
{
continue;
}
if (!neighborNode.IsWalkable())
{
closedList.Add(neighborNode);
continue;
}
int tentativeGCost = currentNode.GetGCost() + CalculateDistance(currentNode.GetGridPosition(), neighborNode.GetGridPosition());
if (tentativeGCost < neighborNode.GetGCost())
{
neighborNode.SetCameFromPathNode(currentNode);
neighborNode.SetGCost(tentativeGCost);
neighborNode.SetHCost(CalculateDistance(neighborNode.GetGridPosition(), endGridPosition));
neighborNode.CalculateFCost();
if (!openList.Contains(neighborNode))
{
openList.Add(neighborNode);
}
}
}
}
//No path found
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 GridSystem<PathNode> GetGridSystem(int floor)
{
return gridSystemList[floor];
}
private PathNode GetNode(int x, int z, int floor)
{
return GetGridSystem(floor).GetGridObject(new GridPosition(x, z, floor));
}
private List<PathNode> GetNeighborList(PathNode currentNode)
{
List<PathNode> neighborList = new List<PathNode>();
GridPosition gridPosition = currentNode.GetGridPosition();
if (gridPosition.x - 1 >= 0)
{
//left node
neighborList.Add(GetNode(gridPosition.x - 1, gridPosition.z + 0, gridPosition.floor));
if (gridPosition.z - 1 >= 0)
{
//left down node
neighborList.Add(GetNode(gridPosition.x - 1, gridPosition.z - 1, gridPosition.floor));
}
if (gridPosition.z + 1 < height)
{
//left up node
neighborList.Add(GetNode(gridPosition.x - 1, gridPosition.z + 1, gridPosition.floor));
}
}
if (gridPosition.x + 1 < width)
{
//right node
neighborList.Add(GetNode(gridPosition.x + 1, gridPosition.z + 0, gridPosition.floor));
if (gridPosition.z - 1 >= 0)
{
//right down node
neighborList.Add(GetNode(gridPosition.x + 1, gridPosition.z - 1, gridPosition.floor));
}
if (gridPosition.z + 1 < height)
{
//right up node
neighborList.Add(GetNode(gridPosition.x + 1, gridPosition.z + 1, gridPosition.floor));
}
}
if (gridPosition.z - 1 >= 0)
{
//down node
neighborList.Add(GetNode(gridPosition.x + 0, gridPosition.z - 1, gridPosition.floor));
}
if (gridPosition.z + 1 < height)
{
//up node
neighborList.Add(GetNode(gridPosition.x + 0, gridPosition.z + 1, gridPosition.floor));
}
List<PathNode> totalNeighborList = new List<PathNode>();
totalNeighborList.AddRange(neighborList);
foreach (PathNode pathNode in neighborList)
{
GridPosition neighborGridPosition = pathNode.GetGridPosition();
if (neighborGridPosition.floor - 1 >= 0)
{
totalNeighborList.Add(GetNode(neighborGridPosition.x, neighborGridPosition.z, neighborGridPosition.floor - 1));
}
if (neighborGridPosition.floor + 1 <= floorAmount)
{
totalNeighborList.Add(GetNode(neighborGridPosition.x, neighborGridPosition.z, neighborGridPosition.floor + 1));
}
}
return totalNeighborList;
}
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 void SetIsWalkableGridPosition(GridPosition gridPosition, bool isWalkable)
{
GetGridSystem(gridPosition.floor).GetGridObject(gridPosition).SetIsWalkable(isWalkable);
}
public bool IsWalkableGridPosition(GridPosition gridPosition)
{
return GetGridSystem(gridPosition.floor).GetGridObject(gridPosition).IsWalkable();
}
public bool HasPath(GridPosition startGridPosition, GridPosition endGridPosition)
{
return FindPath(startGridPosition, endGridPosition, out int pathLength) != null;
}
public int GetPathLength(GridPosition startGridPosition, GridPosition endGridPosition)
{
FindPath(startGridPosition, endGridPosition, out int pathLength);
return pathLength;
}
}
And this is the move:
public class MoveAction : BaseAction
{
public event EventHandler OnStartMoving;
public event EventHandler OnStopMoving;
[SerializeField]
private float moveSpeed = 4;
[SerializeField]
private float rotateSpeed = 10f;
[SerializeField]
private int maxMoveDistance = 4;
private StealthRange stealthRange;
private CameraController cam;
private List<Vector3> positionList;
private int currentPositionIndex;
private void Start()
{
stealthRange = GetComponentInChildren<StealthRange>();
cam = FindObjectOfType<CameraController>();
}
public void Update()
{
if (!isActive)
{
return;
}
Vector3 targetPosition = positionList[currentPositionIndex];
Vector3 moveDirection = (targetPosition - transform.position).normalized;
transform.forward = Vector3.Lerp(transform.forward, moveDirection, Time.deltaTime * rotateSpeed);
float stopDistance = 0.1f;
if (Vector3.Distance(targetPosition, transform.position) > stopDistance)
{
transform.position += (moveDirection * moveSpeed) * Time.deltaTime;
}
else
{
currentPositionIndex++;
if (currentPositionIndex >= positionList.Count)
{
OnStopMoving?.Invoke(this, EventArgs.Empty);
ActionComplete();
}
}
}
public override void TakeAction(GridPosition gridPosition, Action onActionComplete)
{
if (!unit.IsEnemy())
{
stealthRange.StealthOff();
}
List<GridPosition> pathGridPositionList = Pathfinding.Instance.FindPath(unit.GetGridPosition(), gridPosition, out int pathLength);
currentPositionIndex = 0;
positionList = new List<Vector3>();
foreach(GridPosition pathGridPosition in pathGridPositionList)
{
positionList.Add(LevelGrid.Instance.GetWorldPosition(pathGridPosition));
}
OnStartMoving?.Invoke(this, EventArgs.Empty);
ActionStart(onActionComplete);
}
public override List<GridPosition> GetValidActionGridPositionList()
{
List<GridPosition> validGridPositionList = new List<GridPosition>();
GridPosition unitGridPosition = unit.GetGridPosition();
for (int x = -maxMoveDistance; x <= maxMoveDistance; x++)
{
for (int z = -maxMoveDistance; z <= maxMoveDistance; z++)
{
for (int floor = -maxMoveDistance; floor <= maxMoveDistance; floor++)
{
GridPosition offsetGridPosition = new GridPosition(x, z, floor);
GridPosition testGridPosition = unitGridPosition + offsetGridPosition;
if (!LevelGrid.Instance.IsValidGridPosition(testGridPosition))
{
continue;
}
//check if unit already in square
if (unitGridPosition == testGridPosition)
{
continue;
}
if (LevelGrid.Instance.HasAnyUnitOnGridPosition(testGridPosition))
{
//Grid already has unit
continue;
}
if (!Pathfinding.Instance.IsWalkableGridPosition(testGridPosition))
{
continue;
}
if (!Pathfinding.Instance.HasPath(unitGridPosition, testGridPosition))
{
continue;
}
int pathfindingDistanceMultiplier = 10;
if (Pathfinding.Instance.GetPathLength(unitGridPosition, testGridPosition) > maxMoveDistance * pathfindingDistanceMultiplier)
{
//path too far
continue;
}
validGridPositionList.Add(testGridPosition);
}
}
}
return validGridPositionList;
}
public override string GetActionName()
{
return "Move";
}
public override EnemyAIAction GetEnemyAIAction(GridPosition gridPosition)
{
int targetCountAtGridPosition = unit.GetAction<ShootAction>().GetTargetCountAtPosition(gridPosition);
return new EnemyAIAction
{
gridPosition = gridPosition,
actionValue = targetCountAtGridPosition * 10,
};
}
}
I went through it and didn’t see anything different but reading github changes is not my forte. haha