using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;
public class ShootAction : BaseAction
{
public event EventHandler<onShootEventArgs> onShoot;
public static event EventHandler<onShootEventArgs> onAnyShoot;
public class onShootEventArgs : EventArgs {
public Unit targetUnit;
public Unit shootingUnit;
}
private enum State {
Idle,
Aiming,
Shooting,
Cooloff
}
private State state;
private float stateTimer;
private Unit targetUnit;
private bool canShootBullet;
float shootingStateTime = 0.1f;
float cooloffStateTime = 0.5f;
float aimingStateTime = 1f;
private Vector3 aimStartDirectionVector;
private Vector3 aimEndDirectionVector;
private void Start() {
actionCost = 1;
maxDistance = (Range)7;
}
private void Update() {
if (!IsActive()) {
return;
}
stateTimer -= Time.deltaTime;
switch (state) {
case State.Aiming:
float rotateSpeed = 2;
float timeElapsed = (aimingStateTime - stateTimer) * rotateSpeed;
if (timeElapsed > aimingStateTime) {
timeElapsed = aimingStateTime;
}
transform.forward = Vector3.Lerp(aimStartDirectionVector
,aimEndDirectionVector
,timeElapsed / aimingStateTime) ;
break;
case State.Shooting:
if (canShootBullet) {
Shoot();
canShootBullet = false;
}
break;
}
if (IsStateTimerElapsed()) {
NextState();
}
}
private void NextState() {
switch (state) {
case State.Idle:
aimStartDirectionVector = transform.forward;
aimEndDirectionVector = ( targetUnit.GetWorldPosition() - transform.position).normalized;
state = State.Aiming;
canShootBullet = true;
SetTimer(aimingStateTime);
break;
case State.Aiming:
state = State.Shooting;
SetTimer(shootingStateTime);
break;
case State.Shooting:
state = State.Cooloff;
SetTimer(cooloffStateTime);
break;
case State.Cooloff:
StopAction();
//state = State.Idle;
break;
}
}
public void Shoot() {
onShoot?.Invoke(this, new onShootEventArgs{
targetUnit = targetUnit,
shootingUnit = unit
});
onAnyShoot?.Invoke(this, new onShootEventArgs{
targetUnit = targetUnit,
shootingUnit = unit
});
targetUnit.Damage(40);
}
private bool IsStateTimerElapsed() => (stateTimer <= 0f);
private void SetTimer(float time) {
stateTimer = time;
}
public override CancellationToken TakeAction(in GridPosition targetGridPosition, out CancellationToken cancellationToken) {
targetUnit = LevelGrid.Instance.GetUnitAtGridPosition(targetGridPosition);
NextState();
StartAction(out cancellationToken).Register(() => {
state = State.Idle;
});
return cancellationToken;
}
public override string GetActionName() {
return "Shoot";
}
protected override bool IsValidTargetPositionSpecific(in GridPosition unitGridPosition, in GridPosition testGridPosition) {
return (LevelGrid.Instance.HasAnyUnitOnGridPosition(testGridPosition)
&& (LevelGrid.Instance.GetUnitAtGridPosition(testGridPosition).IsEnemy() != unit.IsEnemy())
&& (IsClearShot(unitGridPosition, testGridPosition))
);
}
public bool IsClearShot(in GridPosition unitGridPosition, in GridPosition testGridPosition) {
float unitShoulderHeight = 1.7f;
return LevelGrid.Instance.IsLineOfSight(unitGridPosition, testGridPosition, unitShoulderHeight);
}
public Unit GetTargetUnit() => targetUnit;
public override EnemyAIAction GetEnemyAIAction(GridPosition gridPosition) =>
new EnemyAIAction {
gridPosition = gridPosition,
actionValue = 100 + Mathf.RoundToInt((1 - LevelGrid.Instance.GetUnitAtGridPosition(gridPosition).GetHealthNormilized()) * 100f),
};
public int GetTargetCountAtPosition(GridPosition gridPosition) =>
GetValidActionGridPosition(gridPosition).Count();
}