using System; using System.Collections.Generic; using Grid; using UnityEngine; namespace Actions { public class ShootAction : BaseAction { private enum State { Aiming, Shooting, Cooloff } public Unit TargetUnit { get; private set; } public int MaxShootDistance { get; private set; } = 7; private State state; private float stateTimer; private bool canShootBullet; private const float rotationSpeed = 10f; private const float shootingStateTime = .2f; private const float coolOffStateTime = 1f; private const float aimingStateTime = 1.5f; public event EventHandler OnShoot; public class OnShootEventArgs : EventArgs { public Unit TargetUnit; public Unit ShootingUnit; } protected override void Awake() { base.Awake(); ActionName = "Shoot"; } private void Update() { if (!IsActive) return; stateTimer -= Time.deltaTime; switch (state) { case State.Aiming: Vector3 aimDirection = (TargetUnit.GetWorldPosition() - Unit.GetWorldPosition()).normalized; transform.forward = Vector3.Lerp(transform.forward, aimDirection, rotationSpeed * Time.deltaTime); break; case State.Shooting: if (canShootBullet) { Shoot(); canShootBullet = false; } break; case State.Cooloff: break; } if (stateTimer <= 0f) NextState(); } private void Shoot() { OnShoot?.Invoke(this,new(){TargetUnit = TargetUnit, ShootingUnit = Unit}); TargetUnit.Damage(40); } private void NextState() { switch (state) { case State.Aiming: state = State.Shooting; stateTimer = shootingStateTime; break; case State.Shooting: state = State.Cooloff; stateTimer = coolOffStateTime; break; case State.Cooloff: ActionComplete(); break; } } public override void TakeAction(GridPosition gridPosition, Action onActionComplete) { IsActive = true; TargetUnit = LevelGrid.Instance.GetUnitAtGridPosition(gridPosition); canShootBullet = true; state = State.Aiming; stateTimer = aimingStateTime; ActionStart(onActionComplete); } public override List GetValidActionGridPositionList() => GetValidActionGridPositionList(Unit.GridPosition); private List GetValidActionGridPositionList(GridPosition unitGridPosition) { List validGridPositionList = new(); for (int x = -MaxShootDistance; x <= MaxShootDistance; x++) { for (int z = -MaxShootDistance; z <= MaxShootDistance; z++) { GridPosition offsetGridPosition = new(x, z); GridPosition testGridPosition = unitGridPosition + offsetGridPosition; if (!LevelGrid.Instance.IsValidGridPosition(testGridPosition)) continue; //Only return valid grid positions if (Mathf.Abs(x) + Mathf.Abs(z) > MaxShootDistance) continue; //Out of Range if (!LevelGrid.Instance.HasAnyUnitOnGridPosition(testGridPosition)) continue; //Grid position is empty, no unit Unit unitAtGridPosition = LevelGrid.Instance.GetUnitAtGridPosition(testGridPosition); if (unitAtGridPosition.IsEnemy == Unit.IsEnemy) continue; //Both units are on the same 'team' validGridPositionList.Add(testGridPosition); } } return validGridPositionList; } public override EnemyAIAction GetEnemyAIAction(GridPosition gridPosition) { Unit targetUnit = LevelGrid.Instance.GetUnitAtGridPosition(gridPosition); return new(gridPosition, 100 + Mathf.RoundToInt((1 - targetUnit.HealthSystem.HealthNormalized) * 100f)); } public int GetTargetCountAtPosition(GridPosition gridPosition) => GetValidActionGridPositionList(gridPosition).Count; } }