190 lines
6.6 KiB
C#
190 lines
6.6 KiB
C#
using System.Collections;
|
|
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
using TMPro;
|
|
|
|
/// <summary>
|
|
/// 보스 카운터 시스템의 연출/UI를 담당합니다.
|
|
/// 카운터 발동 시 보스 대사, 화면 효과 등을 처리합니다.
|
|
///
|
|
/// "...또 그 수법이냐" 같은 대사로 "보스가 기억한다"는 서사 전달.
|
|
/// </summary>
|
|
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;
|
|
}
|
|
}
|