Kursach_StealthAction/Assets/Scripts/BlindMutantAI.cs

228 lines
7.3 KiB
C#

using UnityEngine;
using UnityEngine.AI;
public class BlindMutantAI : MonoBehaviour
{
private NavMeshAgent agent;
private Animator animator;
[Header("Настройки скорости")]
public float walkSpeed = 2f;
public float runSpeed = 5f;
[Header("Патрулирование")]
public Transform[] patrolPoints;
private int currentPatrolIndex;
private bool isInvestigating = false;
[Header("Обнаружение игрока")]
public float detectionRadius = 3.5f; // Радиус обостренных чувств (слух/запах в упор)
public float losePlayerDistance = 14f; // Дистанция потери цели
private Transform targetPlayer;
private PlayerHealth targetPlayerHealth;
[Header("Настройки атаки")]
public float attackRange = 1.8f; // Дистанция ближнего боя
public float attackDamage = 20f; // Урон за один удар
public float attackCooldown = 1.2f; // Кулдаун между ударами
private float nextAttackTime = 0f;
void Start()
{
agent = GetComponent<NavMeshAgent>();
agent.speed = walkSpeed;
animator = GetComponentInChildren<Animator>();
// Автоматически находим игрока на сцене
var playerObj = FindAnyObjectByType<PlayerHealth>();
if (playerObj != null)
{
targetPlayerHealth = playerObj;
}
if (patrolPoints != null && patrolPoints.Length > 0)
{
GoToNextPatrolPoint();
}
}
void Update()
{
UpdateAnimator();
// 1. Поведение при активном преследовании игрока
if (targetPlayer != null)
{
HandlePlayerChaseAndAttack();
return;
}
// 2. Проверка близости игрока (если подошел слишком близко — чует даже слепой)
CheckProximityDetection();
// 3. Патрулирование и расследование звуков
HandlePatrolAndInvestigation();
}
private void UpdateAnimator()
{
if (animator == null) return;
float currentSpeed = agent != null && agent.enabled ? agent.velocity.magnitude : 0f;
animator.SetFloat("Speed", currentSpeed);
}
private void HandlePlayerChaseAndAttack()
{
if (targetPlayerHealth != null && targetPlayerHealth.IsDead)
{
LosePlayerTarget();
return;
}
float distanceToPlayer = Vector3.Distance(transform.position, targetPlayer.position);
// Игрок убежал слишком далеко
if (distanceToPlayer > losePlayerDistance)
{
LosePlayerTarget();
return;
}
// Игрок в зоне удара
if (distanceToPlayer <= attackRange)
{
agent.isStopped = true;
// Разворачиваемся к игроку
Vector3 lookDirection = targetPlayer.position - transform.position;
lookDirection.y = 0f;
if (lookDirection.sqrMagnitude > 0.001f)
{
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(lookDirection), Time.deltaTime * 10f);
}
// Наносим урон по кулдауну
if (Time.time >= nextAttackTime)
{
nextAttackTime = Time.time + attackCooldown;
if (animator != null)
{
animator.SetTrigger("Attack");
}
if (targetPlayerHealth != null)
{
targetPlayerHealth.TakeDamage(attackDamage);
Debug.Log($"Мутант нанес удар игроку! Урон: {attackDamage}");
}
}
}
else
{
// Бежим к игроку
agent.isStopped = false;
agent.speed = runSpeed;
agent.SetDestination(targetPlayer.position);
}
}
private void CheckProximityDetection()
{
if (targetPlayerHealth == null || targetPlayerHealth.IsDead) return;
float distance = Vector3.Distance(transform.position, targetPlayerHealth.transform.position);
if (distance <= detectionRadius)
{
EngagePlayer(targetPlayerHealth.transform);
}
}
private void HandlePatrolAndInvestigation()
{
if (!agent.pathPending && agent.remainingDistance < 0.5f)
{
if (isInvestigating)
{
isInvestigating = false;
agent.speed = walkSpeed;
if (patrolPoints != null && patrolPoints.Length > 0)
{
GoToNextPatrolPoint();
}
}
else if (patrolPoints != null && patrolPoints.Length > 0)
{
GoToNextPatrolPoint();
}
}
}
private void EngagePlayer(Transform playerTransform)
{
targetPlayer = playerTransform;
if (targetPlayerHealth == null)
{
targetPlayerHealth = playerTransform.GetComponent<PlayerHealth>();
}
isInvestigating = false;
agent.isStopped = false;
agent.speed = runSpeed;
agent.SetDestination(targetPlayer.position);
Debug.Log("Мутант обнаружил игрока и начинает атаку!");
}
private void LosePlayerTarget()
{
targetPlayer = null;
agent.isStopped = false;
agent.speed = walkSpeed;
isInvestigating = false;
if (patrolPoints != null && patrolPoints.Length > 0)
{
GoToNextPatrolPoint();
}
Debug.Log("Мутант потерял игрока и возвращается к патрулированию.");
}
private void GoToNextPatrolPoint()
{
if (patrolPoints == null || patrolPoints.Length == 0) return;
agent.destination = patrolPoints[currentPatrolIndex].position;
currentPatrolIndex = (currentPatrolIndex + 1) % patrolPoints.Length;
}
public void HearSound(Vector3 soundPosition)
{
// Если уже бьем игрока в упор, не отвлекаемся на случайный шум вдалеке
if (targetPlayer != null && Vector3.Distance(transform.position, targetPlayer.position) <= attackRange)
{
return;
}
isInvestigating = true;
agent.isStopped = false;
agent.speed = runSpeed;
agent.SetDestination(soundPosition);
}
public void OnDamagedByPlayer(Transform player)
{
if (animator != null)
{
animator.SetTrigger("GetHit");
}
EngagePlayer(player);
}
private void OnDrawGizmosSelected()
{
// Радиус ближнего обнаружения
Gizmos.color = Color.yellow;
Gizmos.DrawWireSphere(transform.position, detectionRadius);
// Радиус атаки
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(transform.position, attackRange);
}
}