182 lines
4.4 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|