using System.Collections; using UnityEngine; using UnityEngine.AI; public class EnemyAttack : MonoBehaviour { [Header("Attack Settings")] [SerializeField] private float attackRange = 2f; [SerializeField] private float attackRate = 2f; [SerializeField] private float attackDamage = 10f; [SerializeField] private float attackAngle = 45f; [Header("References")] [SerializeField] private Transform player; [SerializeField] private Animator animator; [SerializeField] private NavMeshAgent agent; private float lastAttackTime = 0f; private bool canAttack = true; private bool isAttacking = false; private float attackCooldownTimer = 0f; private PlayerSkillHandler skillHandler; void Start() { // Najdi reference GameObject playerObject = GameObject.FindWithTag("Player"); if (playerObject != null) { player = playerObject.transform; } skillHandler = player.GetComponent(); if (animator == null) animator = GetComponent(); if (agent == null) agent = GetComponent(); lastAttackTime = -attackRate; // Umožní útok hned na začátku } void Update() { // Update cooldown timeru if (!canAttack) { attackCooldownTimer -= Time.deltaTime; if (attackCooldownTimer <= 0f) { canAttack = true; } } } public float GetAttackRange() => attackRange; // Metoda pro pokus o útok - volána z EnemyMovement public bool TryAttack() { if (player == null || !canAttack || isAttacking) { Debug.Log($"Attack failed: player={player != null}, canAttack={canAttack}, isAttacking={isAttacking}"); return false; } // Kontrola vzdálenosti a úhlu k hráči float distanceToPlayer = Vector3.Distance(transform.position, player.position); bool inRange = IsPlayerInAttackRange(); bool inAngle = IsPlayerInAttackAngle(); bool cooldownReady = Time.time - lastAttackTime >= attackRate; if (inRange && cooldownReady) { StartCoroutine(PerformAttack()); return true; } Debug.Log("Attack conditions not met. Conditions: range: " + inRange + "angle: " + inAngle + "cooldown: " + cooldownReady); return false; } private bool IsPlayerInAttackAngle() { if (player == null) return false; Vector3 directionToPlayer = (player.position - transform.position).normalized; // Ignoruj Y osu pro výpočet úhlu directionToPlayer.y = 0; Vector3 forward = transform.forward; forward.y = 0; float angle = Vector3.Angle(forward, directionToPlayer); return angle <= attackAngle; // Používáme celý attackAngle, ne polovinu } public bool IsPlayerInAttackRange() { if (player == null) return false; float distance = Vector3.Distance(transform.position, player.position); bool inRange = distance <= attackRange * 1.2f; return inRange; } private IEnumerator PerformAttack() { isAttacking = true; canAttack = false; lastAttackTime = Time.time; attackCooldownTimer = attackRate; // Ulož původní stav agenta bool wasStopped = agent.isStopped; // Zastav pohyb během útoku agent.isStopped = true; // Spustit animaci útoku if (animator != null) { animator.SetTrigger("Attack"); } // Počkej chvíli před aplikováním poškození yield return new WaitForSeconds(0.1f); bool playerDashing = skillHandler.IsDashing(); // Aplikuj poškození, pokud je hráč stále v dosahu if (player != null && Vector3.Distance(transform.position, player.position) <= attackRange * 1.2f && !playerDashing) { var health = player.GetComponent(); if (health != null) { health.ModifyHealth(-attackDamage); Debug.Log("Enemy attacked player for " + attackDamage + " damage!"); } } // Počkej na dokončení animace yield return new WaitForSeconds(0.3f); // Obnov pohyb pouze pokud nebyl původně zastavený if (!wasStopped) { agent.isStopped = false; } isAttacking = false; // canAttack se nastaví v Update pomocí timeru Debug.Log("Attack finished, cooldown started"); } // Metoda pro vizuální reprezentaci útočného úhlu private void OnDrawGizmosSelected() { Gizmos.color = Color.red; Gizmos.DrawWireSphere(transform.position, attackRange); Gizmos.color = Color.yellow; Vector3 leftDir = Quaternion.Euler(0, -attackAngle / 2, 0) * transform.forward; Vector3 rightDir = Quaternion.Euler(0, attackAngle / 2, 0) * transform.forward; Gizmos.DrawRay(transform.position, leftDir * attackRange); Gizmos.DrawRay(transform.position, rightDir * attackRange); Gizmos.DrawLine(transform.position + leftDir * attackRange, transform.position + rightDir * attackRange); } // Public metody pro komunikaci s EnemyMovement public bool CanAttack() { return canAttack && !isAttacking && IsPlayerInAttackRange(); } public bool IsAttacking() { return isAttacking; } public float GetCooldownProgress() { return Mathf.Clamp01(attackCooldownTimer / attackRate); } public void SetAttackState(bool state) { canAttack = state; if (!state) isAttacking = false; } }