using System.Collections; using UnityEngine; using UnityEngine.AI; /// /// Искусственный интеллект уникального Босса 2-го уровня («Тип-0: Альфа-Мутант / Патриарх»). /// Механики: /// 1. Мощная рукопашная атака (40 урона) вблизи. /// 2. Дальняя атака: кислотный плевок с созданием волны эхолокации при ударе и ядовитой лужи. /// 3. Акустическое ослепление (Blackout Screech): оглушающий крик, полностью блокирующий эхолокацию на 4.5с. /// 4. Изолированная комната-арена с карантинной блокировкой дверей до победы над боссом. /// [RequireComponent(typeof(NavMeshAgent))] [RequireComponent(typeof(MutantHealth))] public class TitanBossAI : MonoBehaviour { [Header("Идентификация босса")] public string bossDisplayName = "ТИП-0: АЛЬФА-МУТАНТ (ПАТРИАРХ)"; [Header("Параметры движения")] public float walkSpeed = 2.8f; public float runSpeed = 4.6f; public float stoppingDistance = 2.0f; [Header("Ближний бой")] public float meleeRange = 2.4f; public float meleeDamage = 18f; public float meleeCooldown = 2.2f; private float nextMeleeTime = 0f; [Header("Дальний бой (Кислотный плевок)")] public float spitMinDistance = 5.0f; public float spitCooldown = 8.5f; public float spitDamage = 14f; private float nextSpitTime = 0f; [Header("Акустическое ослепление (Крик слепоты)")] public float screechCooldown = 17f; public float blindnessDuration = 4.5f; private float nextScreechTime = 0f; private bool hasEnragedBelowHalf = false; [Header("Ссылки на компоненты")] public Transform mouthSpawnPoint; public BossArenaController arenaController; private NavMeshAgent agent; private Animator animator; private MutantHealth health; private Transform player; private PlayerHealth playerHealth; public enum BossState { Dormant, Roaring, Combat, Screeching, Spitting, Dead } public BossState CurrentState { get; private set; } = BossState.Dormant; private void Awake() { agent = GetComponent(); animator = GetComponentInChildren(); health = GetComponent(); // Увеличиваем здоровье босса (200 HP) health.maxHealth = 200f; } private void Start() { // Игрок GameObject pObj = GameObject.FindWithTag("Player") ?? GameObject.Find("Player"); if (pObj != null) { player = pObj.transform; playerHealth = pObj.GetComponent(); } if (agent != null) { agent.speed = walkSpeed; agent.stoppingDistance = stoppingDistance; agent.isStopped = true; if (!agent.isOnNavMesh) { if (NavMesh.SamplePosition(transform.position, out NavMeshHit hit, 5.0f, NavMesh.AllAreas)) { agent.Warp(hit.position); } } } // Подписываемся на события здоровья if (health != null) { health.OnHealthChanged += HandleHealthChanged; health.OnDied += HandleDeath; } // Назначаем точку рта для плевка прямо в пасти головы монстра if (mouthSpawnPoint == null) { Transform headBone = null; foreach (var t in GetComponentsInChildren()) { if (t.name == "head") { headBone = t; break; } } GameObject mouth = new GameObject("MouthPoint"); if (headBone != null) { mouth.transform.SetParent(headBone, false); // Смещение в пасть монстра относительно кости головы mouth.transform.localPosition = new Vector3(-0.08f, 0.25f, 0.32f); } else { mouth.transform.SetParent(transform, false); mouth.transform.localPosition = new Vector3(0f, 2.75f, 0.55f); } mouthSpawnPoint = mouth.transform; } nextSpitTime = Time.time + 4f; nextScreechTime = Time.time + 12f; } /// /// Вызывается триггером комнаты, когда игрок заходит на арену и двери блокируются /// public void WakeUp() { if (CurrentState != BossState.Dormant) return; StartCoroutine(RoutineWakeUpRoar()); } private IEnumerator RoutineWakeUpRoar() { CurrentState = BossState.Roaring; // Поворачиваемся к игроку if (player != null) { Vector3 lookDir = (player.position - transform.position); lookDir.y = 0; if (lookDir.sqrMagnitude > 0.01f) transform.rotation = Quaternion.LookRotation(lookDir); } // Рев пробуждения GameAudioSynthesizer.PlayBossRoar(); // Отображаем здоровье на экране if (BossHealthBarUI.Instance != null && health != null) { BossHealthBarUI.Instance.ShowBoss(bossDisplayName, health.CurrentHealth, health.maxHealth); } // Создаем мощную волну эхолокации от рева if (EchoTrigger.Instance != null) { EchoTrigger.Instance.TriggerExternalWave(transform.position, 28f, 3.5f); } yield return new WaitForSeconds(1.8f); if (CurrentState != BossState.Dead) { CurrentState = BossState.Combat; if (agent != null && agent.isOnNavMesh) agent.isStopped = false; } } private void Update() { if (CurrentState == BossState.Dormant || CurrentState == BossState.Dead) { UpdateAnimationSpeed(0f); return; } if (CurrentState == BossState.Roaring || CurrentState == BossState.Screeching || CurrentState == BossState.Spitting) { UpdateAnimationSpeed(0f); return; } if (player == null || playerHealth == null || playerHealth.IsDead) { if (agent != null && agent.isOnNavMesh) agent.isStopped = true; UpdateAnimationSpeed(0f); return; } float dist = Vector3.Distance(transform.position, player.position); // 1. Проверка на фазовый крик ослепления (Acoustic Blackout Screech) if (Time.time >= nextScreechTime) { StartCoroutine(RoutineAcousticScreech()); return; } // 2. Ближний бой (если подошли в упор) if (dist <= meleeRange) { if (agent != null && agent.isOnNavMesh) agent.isStopped = true; UpdateAnimationSpeed(0f); // Поворот к игроку FaceTarget(player.position); if (Time.time >= nextMeleeTime) { PerformMeleeAttack(); } return; } // 3. Дальний бой (Кислотный плевок) if (dist >= spitMinDistance && Time.time >= nextSpitTime) { StartCoroutine(RoutineSpitAttack()); return; } // 4. Погоня за игроком внутри комнаты if (agent != null && agent.isOnNavMesh) { agent.isStopped = false; agent.speed = runSpeed; agent.SetDestination(player.position); UpdateAnimationSpeed(agent.velocity.magnitude); } } private void PerformMeleeAttack() { nextMeleeTime = Time.time + meleeCooldown; if (animator != null) { animator.SetTrigger("Attack"); } StartCoroutine(RoutineMeleeDamageCheck()); } private IEnumerator RoutineMeleeDamageCheck() { yield return new WaitForSeconds(0.45f); if (CurrentState == BossState.Dead) yield break; if (player != null && playerHealth != null && !playerHealth.IsDead) { float dist = Vector3.Distance(transform.position, player.position); if (dist <= meleeRange + 0.8f) { playerHealth.TakeDamage(meleeDamage); Debug.Log($"[Босс] Сокрушительный удар вблизи! Нанесено {meleeDamage} урона."); // Мощный глухой удар GameAudioSynthesizer.PlayErrorCode(); // Волна от удара о землю if (EchoTrigger.Instance != null) { EchoTrigger.Instance.TriggerExternalWave(transform.position + transform.forward * 1.2f, 15f, 2.0f); } } } } public Vector3 GetMouthPosition() { if (mouthSpawnPoint != null) return mouthSpawnPoint.position; Transform headBone = null; foreach (var t in GetComponentsInChildren()) { if (t.name == "head") { headBone = t; break; } } if (headBone != null) { return headBone.position + transform.forward * 0.45f - Vector3.up * 0.12f; } return transform.position + Vector3.up * 2.75f + transform.forward * 0.55f; } private IEnumerator RoutineSpitAttack() { CurrentState = BossState.Spitting; nextSpitTime = Time.time + spitCooldown; if (agent != null && agent.isOnNavMesh) agent.isStopped = true; // Поворот к цели FaceTarget(player.position); if (animator != null) { animator.SetTrigger("Attack"); } // Звук клокотания в горле перед извержением слюны GameAudioSynthesizer.PlayAcidHiss(); yield return new WaitForSeconds(0.35f); if (CurrentState == BossState.Dead) yield break; // Звук сочного хлёсткого плевка изо рта GameAudioSynthesizer.PlayAcidSpitSound(); // Спавним очередь брызг слюны прямо из пасти босса Vector3 target = player != null ? player.position + Vector3.up * 1.1f : transform.position + transform.forward * 10f; // 1. Основной тяжелый сгусток слюны Vector3 spawn1 = GetMouthPosition(); AcidProjectile.Spawn(spawn1, target, projSpeed: 19f, damage: spitDamage * 0.7f, isMain: true, spreadAngle: 0f); // 2. Вторая капля слюны с легким естественным разлетом yield return new WaitForSeconds(0.06f); if (CurrentState == BossState.Dead) yield break; Vector3 spawn2 = GetMouthPosition(); AcidProjectile.Spawn(spawn2, target, projSpeed: 17.5f, damage: spitDamage * 0.2f, isMain: false, spreadAngle: 3f); // 3. Третья мелкая брызга слюны yield return new WaitForSeconds(0.05f); if (CurrentState == BossState.Dead) yield break; Vector3 spawn3 = GetMouthPosition(); AcidProjectile.Spawn(spawn3, target, projSpeed: 16.5f, damage: spitDamage * 0.1f, isMain: false, spreadAngle: 5f); yield return new WaitForSeconds(0.4f); if (CurrentState != BossState.Dead) { CurrentState = BossState.Combat; if (agent != null && agent.isOnNavMesh) agent.isStopped = false; } } private IEnumerator RoutineAcousticScreech() { CurrentState = BossState.Screeching; nextScreechTime = Time.time + screechCooldown; if (agent != null && agent.isOnNavMesh) agent.isStopped = true; FaceTarget(player.position); Debug.Log("[Босс] АКУСТИЧЕСКИЙ КРИК: ПОЛНОЕ ОСЛЕПЛЕНИЕ ПРОСТРАНСТВА!"); // Оглушительный крик GameAudioSynthesizer.PlayAcousticScreech(); // Активируем полную слепоту в эхолокаторе (эхолокация заблокирована) if (EchoTrigger.Instance != null) { EchoTrigger.Instance.ApplyBlindness(blindnessDuration); } yield return new WaitForSeconds(1.2f); if (CurrentState != BossState.Dead) { CurrentState = BossState.Combat; // Во время слепоты босс яростно бежит на игрока! if (agent != null && agent.isOnNavMesh) { agent.isStopped = false; agent.speed = runSpeed * 1.15f; // Ускоренный рывок в темноте! if (player != null) agent.SetDestination(player.position); } } } private void HandleHealthChanged(float current, float max) { if (BossHealthBarUI.Instance != null) { BossHealthBarUI.Instance.UpdateHealth(current, max); } // Ярость при падении ниже 50% HP: внеочередной крик ослепления if (!hasEnragedBelowHalf && current <= max * 0.5f) { hasEnragedBelowHalf = true; nextScreechTime = Time.time + 0.5f; // Немедленный крик ярости! } } private void HandleDeath() { CurrentState = BossState.Dead; if (agent != null && agent.isOnNavMesh) { agent.isStopped = true; agent.enabled = false; } if (animator != null) { animator.SetBool("IsDead", true); animator.SetTrigger("Die"); } // Скрываем полосу здоровья if (BossHealthBarUI.Instance != null) { BossHealthBarUI.Instance.HideBoss(false); } // Сообщаем контроллеру арены о победе (открытие дверей) if (arenaController != null) { arenaController.OnBossDefeated(); } // Финальная победная волна рассеивания if (EchoTrigger.Instance != null) { EchoTrigger.Instance.TriggerExternalWave(transform.position, 35f, 4.0f); } GameAudioSynthesizer.PlaySuccessChime(); Debug.Log("[Босс] БОСС ПОВЕРЖЕН! Карантинная блокировка снята, шлюз открыт."); } private void FaceTarget(Vector3 targetPos) { Vector3 dir = (targetPos - transform.position); dir.y = 0; if (dir.sqrMagnitude > 0.001f) { Quaternion rot = Quaternion.LookRotation(dir); transform.rotation = Quaternion.Slerp(transform.rotation, rot, 10f * Time.deltaTime); } } private void UpdateAnimationSpeed(float speedVal) { if (animator != null) { animator.SetFloat("Speed", speedVal); } } }