137 lines
5.3 KiB
C#
137 lines
5.3 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using Grid;
|
|
using UnityEngine;
|
|
|
|
namespace Actions {
|
|
public class ShootAction : BaseAction {
|
|
private const float rotationSpeed = 10f;
|
|
private const float shootingStateTime = .2f;
|
|
private const float coolOffStateTime = 1f;
|
|
private const float aimingStateTime = 1.5f;
|
|
private const float unitShoulderHeight = 1.7f;
|
|
|
|
[SerializeField] private LayerMask obstaclesLayerMask;
|
|
private bool canShootBullet;
|
|
|
|
private State state;
|
|
private float stateTimer;
|
|
public Unit TargetUnit { get; private set; }
|
|
public Unit ShootingUnit { get; private set; }
|
|
public int MaxShootDistance { get; private set; }
|
|
|
|
protected override void Awake() {
|
|
base.Awake();
|
|
MaxShootDistance = 7;
|
|
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();
|
|
}
|
|
|
|
|
|
public event EventHandler<ShootEventArgs> OnShoot;
|
|
public static event EventHandler<ShootEventArgs> OnAnyShoot;
|
|
|
|
private void Shoot() {
|
|
OnAnyShoot?.Invoke(this, new() { TargetUnit = TargetUnit, ShootingUnit = Unit });
|
|
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<GridPosition> GetValidActionGridPositionList() => GetValidActionGridPositionList(Unit.GridPosition);
|
|
|
|
private List<GridPosition> GetValidActionGridPositionList(GridPosition unitGridPosition) {
|
|
List<GridPosition> validGridPositionList = new();
|
|
for (int x = -MaxShootDistance; x <= MaxShootDistance; x++) {
|
|
for (int z = -MaxShootDistance; z <= MaxShootDistance; z++) {
|
|
GridPosition offsetGridPosition = new(x, z, 0);
|
|
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'
|
|
TargetUnit = unitAtGridPosition;
|
|
|
|
Vector3 unitWorldPosition = LevelGrid.Instance.GetWorldPosition(unitGridPosition);
|
|
Vector3 shootDir = (TargetUnit.GetWorldPosition() - unitWorldPosition).normalized;
|
|
if (Physics.Raycast(unitWorldPosition + Vector3.up * unitShoulderHeight, shootDir, Vector3.Distance(unitWorldPosition, TargetUnit.GetWorldPosition()), obstaclesLayerMask)) continue; // Blocked by an obstacle
|
|
|
|
validGridPositionList.Add(testGridPosition);
|
|
}
|
|
}
|
|
|
|
return validGridPositionList;
|
|
}
|
|
|
|
protected 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;
|
|
|
|
private enum State {
|
|
Aiming,
|
|
Shooting,
|
|
Cooloff
|
|
}
|
|
|
|
public class ShootEventArgs : EventArgs {
|
|
public Unit ShootingUnit;
|
|
public Unit TargetUnit;
|
|
}
|
|
}
|
|
} |