228 lines
7.3 KiB
C#
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);
|
|
}
|
|
} |