using System.Collections; using UnityEngine; using UnityEngine.AI; public class EnemyMovement : MonoBehaviour { [Header("Navigation")] public NavMeshAgent agent; public Transform player; public float updatePathInterval = 0.5f; public float roomCheckInterval = 2f; [Header("Combat")] public float attackRange = 2f; public float sightRange = 20f; public float patrolRange = 5f; [Header("References")] public EnemyAttack enemyAttack; private enum EnemyState { Patrolling, Chasing, Attacking } private EnemyState currentState = EnemyState.Patrolling; private Vector3 patrolCenter; private Vector3 patrolTarget; private float lastStateChangeTime; private float minAttackStateDuration = 1.0f; [Header("Animation")] public Animator animator; private void Start() { // Najdi hráče GameObject playerObject = GameObject.FindWithTag("Player"); if (playerObject != null) { player = playerObject.transform; } // Najdi EnemyAttack komponentu if (enemyAttack == null) { enemyAttack = GetComponent(); } // Nastav výchozí pozice patrolCenter = transform.position; GenerateNewPatrolTarget(); lastStateChangeTime = Time.time; // Spustit coroutines if (agent != null) { agent.stoppingDistance = attackRange - 0.2f; StartCoroutine(UpdatePath()); StartCoroutine(CheckPlayerInRange()); StartCoroutine(CheckCurrentRoom()); } } private void Update() { if (agent == null) return; // Update animací if (animator != null) { animator.SetFloat("Speed", agent.velocity.magnitude); } // Stavové chování switch (currentState) { case EnemyState.Patrolling: PatrolBehavior(); break; case EnemyState.Chasing: ChaseBehavior(); break; case EnemyState.Attacking: AttackBehavior(); break; } } private void PatrolBehavior() { // Pokud je cíl patrolování dosažen, vyber nový cíl if (!agent.pathPending && agent.remainingDistance <= agent.stoppingDistance) { GenerateNewPatrolTarget(); } // Kontrola, zda hráč není v dohledu i během patrolování if (player != null && enemyAttack != null && enemyAttack.IsPlayerInAttackRange()) { ChangeState(EnemyState.Attacking); } } private void ChaseBehavior() { if (player == null) { ChangeState(EnemyState.Patrolling); return; } float distanceToPlayer = Vector3.Distance(transform.position, player.position); // Přepni do attack stavu pouze pokud může útočit a je v dosahu if (enemyAttack != null && enemyAttack.IsPlayerInAttackRange() && enemyAttack.CanAttack()) { ChangeState(EnemyState.Attacking); return; } if (distanceToPlayer > sightRange * 1.5f) { ChangeState(EnemyState.Patrolling); GenerateNewPatrolTarget(); } } private void AttackBehavior() { if (player == null || enemyAttack == null) { ChangeState(EnemyState.Chasing); return; } // RYCHLEJŠÍ a PŘESNĚJŠÍ otáčení k hráči Vector3 directionToPlayer = (player.position - transform.position).normalized; // Ignoruj Y osu pro rotaci directionToPlayer.y = 0; if (directionToPlayer != Vector3.zero) { Quaternion targetRotation = Quaternion.LookRotation(directionToPlayer); transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, 15f * Time.deltaTime); // Zvýšená rychlost otáčení } // Zkus zaútočit bool attackAttempted = enemyAttack.TryAttack(); float distanceToPlayer = Vector3.Distance(transform.position, player.position); // Zůstaň v attack stavu pokud může útočit nebo se otáčí k hráči if (!attackAttempted && enemyAttack.CanAttack() && enemyAttack.IsPlayerInAttackRange()) { return; } // Pokud je hráč příliš daleko, pokračuj v pronásledování if (distanceToPlayer > attackRange * 1.5f && !enemyAttack.IsAttacking()) { ChangeState(EnemyState.Chasing); } } private IEnumerator CheckPlayerInRange() { while (true) { if (player != null && !enemyAttack.IsAttacking()) { float distanceToPlayer = Vector3.Distance(transform.position, player.position); if (currentState == EnemyState.Patrolling && distanceToPlayer <= sightRange) { ChangeState(EnemyState.Chasing); } else if (currentState == EnemyState.Chasing && distanceToPlayer > sightRange * 1.5f) { ChangeState(EnemyState.Patrolling); } else if (currentState == EnemyState.Chasing && distanceToPlayer <= attackRange && enemyAttack.CanAttack()) { ChangeState(EnemyState.Attacking); } } yield return new WaitForSeconds(0.3f); } } private void ChangeState(EnemyState newState) { if (currentState == newState) return; currentState = newState; lastStateChangeTime = Time.time; // Specifické akce při změně stavu switch (newState) { case EnemyState.Chasing: agent.isStopped = false; break; case EnemyState.Patrolling: agent.isStopped = false; GenerateNewPatrolTarget(); break; } } private IEnumerator UpdatePath() { while (true) { if (currentState == EnemyState.Chasing && player != null && !enemyAttack.IsAttacking()) { agent.SetDestination(player.position); } else if (currentState == EnemyState.Patrolling && !enemyAttack.IsAttacking()) { agent.SetDestination(patrolTarget); } yield return new WaitForSeconds(updatePathInterval); } } private IEnumerator CheckCurrentRoom() { while (true) { if (!agent.isOnNavMesh && !enemyAttack.IsAttacking()) { agent.Warp(transform.position); } yield return new WaitForSeconds(roomCheckInterval); } } private void GenerateNewPatrolTarget() { Vector2 randomCircle = Random.insideUnitCircle * patrolRange; patrolTarget = patrolCenter + new Vector3(randomCircle.x, 0, randomCircle.y); NavMeshHit hit; if (NavMesh.SamplePosition(patrolTarget, out hit, patrolRange, NavMesh.AllAreas)) { patrolTarget = hit.position; } } // Voláno při smrti nepřítele public void Die() { StopAllCoroutines(); if (agent != null) { agent.isStopped = true; } if (enemyAttack != null) { enemyAttack.SetAttackState(false); } Destroy(gameObject, 2f); } private void OnDrawGizmosSelected() { Gizmos.color = Color.red; Gizmos.DrawWireSphere(transform.position, attackRange); Gizmos.color = Color.yellow; Gizmos.DrawWireSphere(transform.position, sightRange); Gizmos.color = Color.blue; Gizmos.DrawWireSphere(patrolCenter, patrolRange); if (Application.isPlaying) { Gizmos.color = Color.green; Gizmos.DrawSphere(patrolTarget, 0.3f); Gizmos.DrawLine(transform.position, patrolTarget); } } private void OnGUI() { if (Application.isPlaying && enemyAttack != null) { GUI.Label(new Rect(10, 30, 300, 20), $"State: {currentState}"); GUI.Label(new Rect(10, 50, 300, 20), $"CanAttack: {enemyAttack.CanAttack()}"); GUI.Label(new Rect(10, 70, 300, 20), $"IsAttacking: {enemyAttack.IsAttacking()}"); GUI.Label(new Rect(10, 90, 300, 20), $"Cooldown: {enemyAttack.GetCooldownProgress():P0}"); if (player != null) { float distance = Vector3.Distance(transform.position, player.position); GUI.Label(new Rect(10, 110, 300, 20), $"Distance: {distance:F2}"); } } } }