Files
tiny_tackle_heroes/Assets/_Project/Scripts/Defense/DefenseRouteAgent.cs
T

197 lines
6.5 KiB
C#

using System;
using BumpCombat.Enemies;
using UnityEngine;
namespace BumpCombat.Defense
{
[DisallowMultipleComponent]
public sealed class DefenseRouteAgent : MonoBehaviour
{
private EnemyController enemy;
private Vector2[] waypoints = Array.Empty<Vector2>();
private Action<DefenseRouteAgent> arrivalHandler;
private Transform player;
private BumpCombat.Player.PlayerHealth playerHealth;
private float routeSpeed;
private float playerEngagementRange;
private float postAttackProgressSeconds;
private float postAttackProgressRemaining;
private bool wasAttackSequenceInProgress;
private bool configured;
private int waypointIndex;
public EnemyController Enemy => enemy;
public int Lane { get; private set; }
public int LifetimeId => enemy != null ? enemy.SpawnLifetimeIdentity : -1;
public DefenseTowerKind ImmuneTowerKind { get; private set; }
public Vector2 AnchorPosition => waypoints.Length > 0 ? waypoints[0] : transform.position;
public bool HasArrived { get; private set; }
public void Configure(
EnemyController configuredEnemy,
int lane,
Vector2[] route,
float speed,
float engagementRange,
float postAttackProgress,
DefenseTowerKind immuneTowerKind,
Action<DefenseRouteAgent> onArrived)
{
enemy = configuredEnemy;
Lane = lane;
waypoints = route ?? Array.Empty<Vector2>();
routeSpeed = Mathf.Max(0.1f, speed);
playerEngagementRange = Mathf.Max(0.1f, engagementRange);
postAttackProgressSeconds = Mathf.Max(0f, postAttackProgress);
postAttackProgressRemaining = 0f;
wasAttackSequenceInProgress = false;
ImmuneTowerKind = immuneTowerKind;
arrivalHandler = onArrived;
waypointIndex = 0;
configured = enemy != null && waypoints.Length > 0;
HasArrived = false;
player = FindAnyObjectByType<BumpCombat.Player.PlayerController>()?.transform;
playerHealth = player != null
? player.GetComponent<BumpCombat.Player.PlayerHealth>()
: null;
if (configured)
{
enemy.TryReposition(waypoints[0]);
}
}
public bool TryDriveFixedUpdate(float deltaTime)
{
if (!configured || HasArrived || enemy == null || enemy.IsDead)
{
return false;
}
if (enemy.State == EnemyState.Spawn)
{
return false;
}
bool attackSequenceActive = enemy.IsAttackSequenceInProgress;
if (attackSequenceActive)
{
wasAttackSequenceInProgress = true;
return false;
}
if (wasAttackSequenceInProgress)
{
wasAttackSequenceInProgress = false;
postAttackProgressRemaining = postAttackProgressSeconds;
}
if (enemy.IsStunned)
{
return false;
}
postAttackProgressRemaining = Mathf.Max(
0f,
postAttackProgressRemaining - Mathf.Max(0f, deltaTime));
if (player == null)
{
player = FindAnyObjectByType<BumpCombat.Player.PlayerController>()?.transform;
playerHealth = player != null
? player.GetComponent<BumpCombat.Player.PlayerHealth>()
: null;
}
if (postAttackProgressRemaining <= 0f
&& player != null
&& playerHealth != null
&& playerHealth.CurrentHealth > 0f
&& (player.position - transform.position).sqrMagnitude
<= playerEngagementRange * playerEngagementRange)
{
enemy.Alert();
return false;
}
if (waypointIndex >= waypoints.Length)
{
CompleteArrival();
return true;
}
Vector2 current = transform.position;
Vector2 target = waypoints[waypointIndex];
Vector2 next = Vector2.MoveTowards(
current,
target,
routeSpeed * enemy.MovementSpeedMultiplier * Mathf.Max(0f, deltaTime));
if (!enemy.TryReposition(next))
{
return false;
}
Vector2 movementDirection = next - current;
if (movementDirection.sqrMagnitude > 0.000001f)
{
enemy.SetFacingDirection(movementDirection);
}
Animator animator = enemy.GetComponent<Animator>();
animator?.SetBool("IsMoving", (next - current).sqrMagnitude > 0.000001f);
if ((target - next).sqrMagnitude <= 0.01f)
{
waypointIndex++;
if (waypointIndex >= waypoints.Length)
{
CompleteArrival();
}
}
return true;
}
public bool TryTakeTowerDamage(
DefenseTowerKind sourceKind,
float requestedDamage,
float distanceToPlayer,
float sightRadius,
float outsideSightEfficiency,
Vector2 sourcePosition)
{
if (!configured
|| HasArrived
|| enemy == null
|| enemy.IsDead
|| DefensePrototypeRules.IsTowerImmune(
sourceKind,
ImmuneTowerKind))
{
return false;
}
float efficiency = DefensePrototypeRules.GetTowerEfficiency(
distanceToPlayer,
sightRadius,
1f,
outsideSightEfficiency);
Vector2 direction = ((Vector2)transform.position - sourcePosition).normalized;
return enemy.TryTakeDamage(
Mathf.Max(0f, requestedDamage) * efficiency,
direction,
0f,
false,
false,
EnemyDamageSource.Tower);
}
private void CompleteArrival()
{
if (HasArrived)
{
return;
}
HasArrived = true;
arrivalHandler?.Invoke(this);
}
}
}