using UnityEngine; // 유니티 기능을 불러올거에요 -> UnityEngine을 using UnityEngine.AI; // 내비게이션 기능을 불러올거에요 -> UnityEngine.AI를 using System.Collections; // 코루틴을 사용할거에요 -> System.Collections를 /// /// 화상, 독, 슬로우, 감전 등의 상태이상을 전담 처리하는 클래스 /// [UPGRADED] 틱 간격(tickInterval) 지원 오버로드 + ApplyPoison 추가 /// public class StatusEffectProcessor // 클래스를 선언할거에요 -> 상태이상 로직을 담당하는 클래스를 { private readonly MonoBehaviour _owner; // 변수를 선언할거에요 -> 코루틴 실행 주체를 private readonly IDamageable _damageable; // 변수를 선언할거에요 -> 데미지 인터페이스를 private readonly NavMeshAgent _agent; // 변수를 선언할거에요 -> 이동 에이전트를 private readonly Animator _animator; // 변수를 선언할거에요 -> 애니메이터를 public StatusEffectProcessor(MonoBehaviour owner, IDamageable damageable, NavMeshAgent agent, Animator animator) // 생성자를 만들거에요 -> 의존성 주입을 위한 { _owner = owner; // 값을 저장할거에요 -> 주인을 _damageable = damageable; // 값을 저장할거에요 -> 데미지 대상을 _agent = agent; // 값을 저장할거에요 -> 에이전트를 _animator = animator; // 값을 저장할거에요 -> 애니메이터를 } // ───────────────────────────────────────────────────────── // 화상 (Burn) // ───────────────────────────────────────────────────────── /// /// [기존] 화상 — 2-파라미터 (하위 호환, 기본 틱 간격 0.5초) /// public void ApplyBurn(float damage, float duration) // 함수를 선언할거에요 -> 화상 적용을 (2-파라미터 버전) { _owner.StartCoroutine(DotRoutine("화상", damage, duration, 0.5f)); // 실행할거에요 -> 기본 틱 간격 0.5초로 도트 코루틴을 } /// /// [NEW] 화상 — 3-파라미터 (틱 간격 지정 가능) /// public void ApplyBurn(float damagePerTick, float duration, float tickInterval) // 함수를 선언할거에요 -> 화상 적용을 (3-파라미터 버전) { _owner.StartCoroutine(DotRoutine("화상", damagePerTick, duration, tickInterval)); // 실행할거에요 -> 지정 틱 간격으로 도트 코루틴을 } // ───────────────────────────────────────────────────────── // 독 (Poison) // ───────────────────────────────────────────────────────── /// /// [NEW] 독 — 2-파라미터 (기본 틱 간격 1초) /// public void ApplyPoison(float damage, float duration) // 함수를 선언할거에요 -> 독 적용을 (2-파라미터 버전) { _owner.StartCoroutine(DotRoutine("독", damage, duration, 1f)); // 실행할거에요 -> 기본 틱 간격 1초로 도트 코루틴을 } /// /// [NEW] 독 — 3-파라미터 (틱 간격 지정 가능) /// public void ApplyPoison(float damagePerTick, float duration, float tickInterval) // 함수를 선언할거에요 -> 독 적용을 (3-파라미터 버전) { _owner.StartCoroutine(DotRoutine("독", damagePerTick, duration, tickInterval)); // 실행할거에요 -> 지정 틱 간격으로 도트 코루틴을 } // ───────────────────────────────────────────────────────── // 슬로우 (Slow) // ───────────────────────────────────────────────────────── /// /// [기존] 슬로우 — 2-파라미터 /// amount: 감속 비율 (0~1 사이 값 또는 0~100 사이 값 모두 지원) /// public void ApplySlow(float amount, float duration) // 함수를 선언할거에요 -> 슬로우 적용을 { _owner.StartCoroutine(SlowRoutine(amount, duration)); // 실행할거에요 -> 슬로우 코루틴을 } // ───────────────────────────────────────────────────────── // 감전/스턴 (Shock) // ───────────────────────────────────────────────────────── /// /// [기존] 감전 — 즉발 데미지 + 스턴 /// public void ApplyShock(float damage, float duration) // 함수를 선언할거에요 -> 감전 적용을 { _damageable.TakeDamage(damage); // 실행할거에요 -> 즉발 데미지를 _owner.StartCoroutine(StunRoutine(duration)); // 실행할거에요 -> 스턴 코루틴을 } // ───────────────────────────────────────────────────────── // 코루틴들 // ───────────────────────────────────────────────────────── /// /// [NEW] 통합 도트 데미지 코루틴 — 화상/독 모두 이것을 사용 /// damagePerTick: 1틱당 데미지 /// duration: 총 지속 시간 (초) /// tickInterval: 틱 간격 (초) /// private IEnumerator DotRoutine(string effectName, float damagePerTick, float duration, float tickInterval) // 코루틴을 정의할거에요 -> 통합 도트 데미지 로직을 { if (tickInterval <= 0f) tickInterval = 0.5f; // 안전장치를 넣을거에요 -> 틱 간격이 0 이하면 0.5초로 float elapsed = 0f; // 변수를 초기화할거에요 -> 경과 시간을 0으로 Debug.Log($"[StatusEffect] {effectName} 시작! 틱당:{damagePerTick} 간격:{tickInterval}초 지속:{duration}초"); // 로그를 출력할거에요 -> 효과 시작 안내를 while (elapsed < duration) // 반복할거에요 -> 지속 시간이 끝날 때까지 { _damageable.TakeDamage(damagePerTick); // 실행할거에요 -> 1틱 데미지를 yield return new WaitForSeconds(tickInterval); // 기다릴거에요 -> 틱 간격만큼 elapsed += tickInterval; // 값을 더할거에요 -> 경과 시간에 틱 간격을 } Debug.Log($"[StatusEffect] {effectName} 종료!"); // 로그를 출력할거에요 -> 효과 종료 안내를 } /// /// [기존] 슬로우 코루틴 /// amount가 1 이하면 비율로(0.5 = 50% 감속), 1 초과면 퍼센트로(50 = 50% 감속) /// private IEnumerator SlowRoutine(float amount, float duration) // 코루틴을 정의할거에요 -> 슬로우 로직을 { if (_agent == null) yield break; // 조건이 맞으면 종료할거에요 -> 에이전트가 없으면 float orgSpeed = _agent.speed; // 값을 저장할거에요 -> 원래 속도를 // amount 해석: 1 이하면 비율(0.5 = 50% 감속), 1 초과면 퍼센트(50 = 50% 감속) float slowRate = amount > 1f ? Mathf.Clamp01(amount / 100f) : Mathf.Clamp01(amount); // 값을 계산할거에요 -> 감속 비율을 _agent.speed *= (1f - slowRate); // 값을 바꿀거에요 -> 속도를 줄여서 Debug.Log($"[StatusEffect] 슬로우! 원래:{orgSpeed} → 감속:{_agent.speed} ({slowRate * 100}% 감속) {duration}초간"); // 로그를 출력할거에요 -> 슬로우 내역을 yield return new WaitForSeconds(duration); // 기다릴거에요 -> 지속 시간만큼 _agent.speed = orgSpeed; // 값을 복구할거에요 -> 원래 속도로 Debug.Log($"[StatusEffect] 슬로우 해제! 속도 복구: {orgSpeed}"); // 로그를 출력할거에요 -> 해제 안내를 } /// /// [기존] 스턴 코루틴 — 이동 정지 + 애니 멈춤 /// private IEnumerator StunRoutine(float duration) // 코루틴을 정의할거에요 -> 스턴 로직을 { if (_agent != null) _agent.isStopped = true; // 명령을 내릴거에요 -> 이동 정지를 if (_animator != null) _animator.speed = 0; // 값을 바꿀거에요 -> 애니 속도를 0으로 Debug.Log($"[StatusEffect] 스턴! {duration}초간 행동 불능"); // 로그를 출력할거에요 -> 스턴 안내를 yield return new WaitForSeconds(duration); // 기다릴거에요 -> 스턴 시간만큼 if (_agent != null && _agent.isOnNavMesh) _agent.isStopped = false; // 명령을 내릴거에요 -> 이동 재개를 if (_animator != null) _animator.speed = 1; // 값을 바꿀거에요 -> 애니 속도 복구를 Debug.Log($"[StatusEffect] 스턴 해제!"); // 로그를 출력할거에요 -> 해제 안내를 } }