using System.Collections; using UnityEngine; using UnityEngine.UI; using TMPro; /// /// 보스 카운터 시스템의 연출/UI를 담당합니다. /// 카운터 발동 시 보스 대사, 화면 효과 등을 처리합니다. /// /// "...또 그 수법이냐" 같은 대사로 "보스가 기억한다"는 서사 전달. /// public class BossCounterFeedback : MonoBehaviour { [Header("참조")] [SerializeField] private BossCounterSystem counterSystem; [Header("UI 요소 (선택)")] [SerializeField] private TextMeshProUGUI bossDialogueText; [SerializeField] private CanvasGroup dialogueCanvasGroup; [SerializeField] private float dialogueDisplayDuration = 3f; [SerializeField] private float dialogueFadeDuration = 0.5f; [Header("카운터별 보스 대사")] [SerializeField] private string[] dodgeCounterDialogues = new string[] { "...또 도망치려는 건가.", "네 발은 이미 읽었다.", "아무리 피해도 소용없어." }; [SerializeField] private string[] aimCounterDialogues = new string[] { "그렇게 오래 노려봐야...", "느린 조준은 빈틈이지.", "시간을 줄 생각은 없다." }; [SerializeField] private string[] pierceCounterDialogues = new string[] { "그 화살은 더 이상 통하지 않아.", "관통? 이번엔 막아주지.", "같은 수를 반복하다니." }; [SerializeField] private string[] habitChangeDialogues = new string[] { "...다른 수를 쓰는 건가.", "흥, 조금은 배운 모양이군.", "이번엔 다르군... 재밌어." }; // ── 잠금 해제 여부에 따른 첫 발동 대사 ── [Header("첫 잠금 해제 시 대사 (서사 강조)")] [SerializeField] private string[] firstUnlockDialogues = new string[] { "...기억했다. 네 버릇을.", "이제 알겠어. 네 전투 방식이.", "한 번이면 충분해. 패턴을 읽었다." }; private Coroutine dialogueCoroutine; private void OnEnable() { if (counterSystem != null) { counterSystem.OnCounterActivated.AddListener(OnCounterActivated); counterSystem.OnCounterDeactivated.AddListener(OnCounterDeactivated); counterSystem.OnHabitChangeRewarded.AddListener(OnHabitChangeRewarded); } } private void OnDisable() { if (counterSystem != null) { counterSystem.OnCounterActivated.RemoveListener(OnCounterActivated); counterSystem.OnCounterDeactivated.RemoveListener(OnCounterDeactivated); counterSystem.OnHabitChangeRewarded.RemoveListener(OnHabitChangeRewarded); } } // ═══════════════════════════════════════════ // 이벤트 핸들러 // ═══════════════════════════════════════════ private void OnCounterActivated(CounterType type) { var persistence = BossCounterPersistence.Instance; // 첫 잠금 해제인지 확인 (총 발동 횟수가 1이면 방금 처음 잠금 해제된 것) bool isFirstUnlock = false; if (persistence != null) { int activations = type switch { CounterType.Dodge => persistence.Data.dodgeCounterActivations, CounterType.Aim => persistence.Data.aimCounterActivations, CounterType.Pierce => persistence.Data.pierceCounterActivations, _ => 0 }; isFirstUnlock = (activations <= 1); } // 대사 선택 string dialogue; if (isFirstUnlock) { dialogue = firstUnlockDialogues[Random.Range(0, firstUnlockDialogues.Length)]; } else { dialogue = type switch { CounterType.Dodge => dodgeCounterDialogues[Random.Range(0, dodgeCounterDialogues.Length)], CounterType.Aim => aimCounterDialogues[Random.Range(0, aimCounterDialogues.Length)], CounterType.Pierce => pierceCounterDialogues[Random.Range(0, pierceCounterDialogues.Length)], _ => "" }; } ShowDialogue(dialogue); // TODO: 여기에 추가 연출 넣기 // - 보스 전용 애니메이션 트리거 (예: animator.SetTrigger("CounterReady")) // - 보스 주변 이펙트 (파티클, 오라 등) // - 카메라 연출 (줌인, 슬로모션 등) // - 사운드 효과 Debug.Log($"[BossCounterFeedback] {type} 카운터 연출 재생" + (isFirstUnlock ? " (첫 잠금 해제!)" : "")); } private void OnCounterDeactivated(CounterType type) { // 카운터 해제 시 연출 (이펙트 종료 등) Debug.Log($"[BossCounterFeedback] {type} 카운터 연출 종료"); } private void OnHabitChangeRewarded() { string dialogue = habitChangeDialogues[Random.Range(0, habitChangeDialogues.Length)]; ShowDialogue(dialogue); Debug.Log("[BossCounterFeedback] 습관 변경 보상 연출!"); } // ═══════════════════════════════════════════ // 대사 표시 // ═══════════════════════════════════════════ private void ShowDialogue(string text) { if (bossDialogueText == null || dialogueCanvasGroup == null) return; if (dialogueCoroutine != null) StopCoroutine(dialogueCoroutine); dialogueCoroutine = StartCoroutine(DialogueRoutine(text)); } private IEnumerator DialogueRoutine(string text) { bossDialogueText.text = text; dialogueCanvasGroup.alpha = 0f; // 페이드 인 float t = 0f; while (t < dialogueFadeDuration) { t += Time.deltaTime; dialogueCanvasGroup.alpha = t / dialogueFadeDuration; yield return null; } dialogueCanvasGroup.alpha = 1f; // 유지 yield return new WaitForSeconds(dialogueDisplayDuration); // 페이드 아웃 t = 0f; while (t < dialogueFadeDuration) { t += Time.deltaTime; dialogueCanvasGroup.alpha = 1f - (t / dialogueFadeDuration); yield return null; } dialogueCanvasGroup.alpha = 0f; } }