2026-01-09 08:45:22 +03:00

182 lines
4.4 KiB
C#

using System.Collections;
using UnityEngine;
[RequireComponent(typeof(Animator))]
public class EnemyCombat : MonoBehaviour, IShootable
{
public enum State
{
Idle,
Combat,
KnockedOut
}
[Header("Params")]
[Range(0f, 1f)] public float knockOutChance = 0.5f;
public float fireInterval = 5f;
public float turnSpeed = 360f;
public Vector2 recoverTimeRange = new Vector2(15f, 25f);
[Header("Refs")]
public Animator animator;
public Gun gun;
public Transform shootOrigin;
public State CurrentState { get; private set; } = State.Idle;
private Transform currentTarget;
private Coroutine shootingCoroutine;
private Coroutine recoverCoroutine;
public bool IsActiveTarget()
{
return CurrentState != State.KnockedOut;
}
public bool IsKnockedOut() => CurrentState == State.KnockedOut;
private void Reset()
{
animator = GetComponent<Animator>();
}
private void Awake()
{
if (animator == null) animator = GetComponent<Animator>();
}
// -------------------------
// API
// -------------------------
public void SetTarget(Transform target)
{
if (CurrentState == State.KnockedOut) return;
currentTarget = target;
if (currentTarget != null)
EnterCombat();
else
ExitCombat();
}
public void TakeHit(Vector3 hitPoint)
{
if (CurrentState == State.KnockedOut) return;
animator?.Play("hit", 0, 0f);
if (Random.value < knockOutChance)
{
KnockOut();
}
}
// âûçûâàåòñÿ èç àíèìàöèè "shoot"
public void OnShoot()
{
if (gun == null || currentTarget == null) return;
Vector3 aimPoint = currentTarget.position + Vector3.up * 1.0f;
gun.ShootAt(aimPoint);
}
// -------------------------
// Internals
// -------------------------
private void EnterCombat()
{
if (CurrentState == State.KnockedOut) return;
CurrentState = State.Combat;
StartShooting();
}
private void ExitCombat()
{
if (CurrentState == State.KnockedOut) return;
CurrentState = State.Idle;
animator?.Play("idle");
StopShooting();
}
private void KnockOut()
{
CurrentState = State.KnockedOut;
animator?.Play("dead", 0, 0f);
StopShooting();
currentTarget = null;
if (recoverCoroutine != null) StopCoroutine(recoverCoroutine);
recoverCoroutine = StartCoroutine(RecoverRoutine());
}
private void Recover()
{
CurrentState = State.Idle;
animator?.Play("up", 0, 0f);
// ïîñëå "up" îí àâòîìàòè÷åñêè âåðí¸òñÿ â idle (ìîæíî â êîíöå "up" Animation Event âûçâàòü ReturnToIdle)
}
private void StartShooting()
{
if (shootingCoroutine != null || gun == null || currentTarget == null) return;
shootingCoroutine = StartCoroutine(ShootingRoutine());
}
private void StopShooting()
{
if (shootingCoroutine != null)
{
StopCoroutine(shootingCoroutine);
shootingCoroutine = null;
}
}
private IEnumerator ShootingRoutine()
{
while (CurrentState == State.Combat && currentTarget != null)
{
// ïîâîðîò ê öåëè
Vector3 dir = currentTarget.position - transform.position;
dir.y = 0f;
if (dir.sqrMagnitude > 0.01f)
{
Quaternion targetRot = Quaternion.LookRotation(dir);
transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRot, turnSpeed * Time.deltaTime);
}
// ïðîèãðûâàåì àíèìàöèþ âûñòðåëà
animator?.Play("shoot", 0, 0f);
yield return new WaitForSeconds(fireInterval);
}
shootingCoroutine = null;
}
private IEnumerator RecoverRoutine()
{
float waitTime = Random.Range(recoverTimeRange.x, recoverTimeRange.y);
yield return new WaitForSeconds(waitTime);
Recover();
recoverCoroutine = null;
}
// îòëàäêà
private void OnDrawGizmosSelected()
{
if (shootOrigin != null && currentTarget != null)
{
Gizmos.color = CurrentState == State.Combat ? Color.green : Color.red;
Gizmos.DrawLine(shootOrigin.position, currentTarget.position);
}
}
}