using System; using System.Collections.Generic; using Grid; using UnityEngine; using UnityEngine.Serialization; namespace Actions { public class MoveAction : BaseAction { private const float moveSpeed = 4f; private const float rotationSpeed = 10f; private const float stoppingDistance = 0.1f; private const int pathfindingDistanceMultiplier = 10; private const float DIFFERENT_FLOORS_TELEPORT_TIMER_MAX = .5f; [FormerlySerializedAs("MaxMoveDistance")] [SerializeField] private int maxMoveDistance = 4; private int currentPositionIndex; private float differentFloorsTeleportTimer; private bool isChangingFloors; private List PositionList { get; set; } protected override void Awake() { base.Awake(); ActionName = "Move"; } private void Update() { if (!IsActive) return; Vector3 targetPosition = PositionList[currentPositionIndex]; if (isChangingFloors) { //Stop and teleport logic differentFloorsTeleportTimer -= Time.deltaTime; Vector3 targetSameFloorPosition = targetPosition; targetSameFloorPosition.y = transform.position.y; Vector3 rotateDirection = (targetSameFloorPosition - Unit.GetWorldPosition()).normalized; transform.forward = Vector3.Slerp(transform.forward, rotateDirection, rotationSpeed * Time.deltaTime); if (differentFloorsTeleportTimer < 0f) { isChangingFloors = false; transform.position = targetPosition; } } else { //Regular move logic Vector3 moveDirection = (targetPosition - Unit.GetWorldPosition()).normalized; transform.forward = Vector3.Slerp(transform.forward, moveDirection, rotationSpeed * Time.deltaTime); //Rotate towards targetPosition transform.position += moveSpeed * Time.deltaTime * moveDirection; //Move towards targetPosition } if (!(Vector3.Distance(targetPosition, Unit.GetWorldPosition()) < stoppingDistance)) return; currentPositionIndex++; if (currentPositionIndex >= PositionList.Count) { OnStopMoving?.Invoke(this, EventArgs.Empty); ActionComplete(); } else { targetPosition = PositionList[currentPositionIndex]; GridPosition targetGridPosition = LevelGrid.Instance.GetGridPosition(targetPosition); GridPosition unitGridPosition = LevelGrid.Instance.GetGridPosition(transform.position); if (targetGridPosition.Floor == unitGridPosition.Floor) return; //Same floor isChangingFloors = true; differentFloorsTeleportTimer = DIFFERENT_FLOORS_TELEPORT_TIMER_MAX; OnChangeFloorsStarted?.Invoke(this, new() { unitGridPosition = unitGridPosition, targetGridPosition = targetGridPosition }); } } public event EventHandler OnStartMoving; public event EventHandler OnStopMoving; public event EventHandler OnChangeFloorsStarted; public override List GetValidActionGridPositionList() { List validGridPositionList = new(); GridPosition unitGridPosition = Unit.GridPosition; for (int xPosition = -maxMoveDistance; xPosition <= maxMoveDistance; xPosition++) { for (int zPosition = -maxMoveDistance; zPosition <= maxMoveDistance; zPosition++) { for (int floor = -maxMoveDistance; floor < maxMoveDistance; floor++) { GridPosition offsetGridPosition = new(xPosition, zPosition, floor); GridPosition testGridPosition = unitGridPosition + offsetGridPosition; if (!LevelGrid.Instance.IsValidGridPosition(testGridPosition)) continue; //Only return valid grid positions if (unitGridPosition == testGridPosition) continue; //Same grid position where the unit is already at if (LevelGrid.Instance.HasAnyUnitOnGridPosition(testGridPosition)) continue; //Grid position already occopied with anther unit if (!Pathfinding.Instance.IsWalkableGridPosition(testGridPosition)) continue; //Obstacle on path if (!Pathfinding.Instance.HasPath(unitGridPosition, testGridPosition)) continue; //No path available if (Pathfinding.Instance.GetPathLength(unitGridPosition, testGridPosition) > maxMoveDistance * pathfindingDistanceMultiplier) continue; //Pathlength is to long validGridPositionList.Add(testGridPosition); } } } return validGridPositionList; } public override void TakeAction(GridPosition gridPosition, Action onMoveCompleted) { List pathGridPositionList = Pathfinding.Instance.FindPath(Unit.GridPosition, gridPosition, out _); currentPositionIndex = 0; PositionList = new(); foreach (GridPosition pathGridPosition in pathGridPositionList) { PositionList.Add(LevelGrid.Instance.GetWorldPosition(pathGridPosition)); } OnStartMoving?.Invoke(this, EventArgs.Empty); ActionStart(onMoveCompleted); } protected override EnemyAIAction GetEnemyAIAction(GridPosition gridPosition) { int targetCountAtGridPosition = Unit.GetAction().GetTargetCountAtPosition(gridPosition); return new(gridPosition, targetCountAtGridPosition * 10); } public class ChangeFloorsStartedEventArgs : EventArgs { public GridPosition targetGridPosition; public GridPosition unitGridPosition; } } }