Degulleo3D/Assets/Scripts/Common/Dialogue/ChatWindowController.cs
2025-05-15 13:35:49 +09:00

253 lines
6.7 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using Random = UnityEngine.Random;
// 대화 데이터 클래스
[Serializable]
public class DialogueStruct
{
public string id; // 대화 고유 ID, 세이브용
public string name;
public string text;
public string nextId;
public string phase; // 단계 (intro, gameplay, end)
}
[Serializable]
public class DialogueData // 전체 데이터 클래스
{
public DialogueData()
{
dialogues = new List<DialogueStruct>();
}
public List<DialogueStruct> dialogues;
}
public enum GamePhase // 단계별로 출력되는 대화가 달라짐
{
Intro, // 인트로 설명문
Gameplay, // 게임 진행 팁? 등
End, // 회고 엔딩
ZeroEnd, // 평판 0 엔딩
FailEnd // 같은 스테이지 3회 실패 엔딩
}
public class ChatWindowController : MonoBehaviour, IPointerClickHandler
{
[SerializeField] private TMP_Text nameText;
[SerializeField] private TMP_Text chatText;
[SerializeField] private Image clickIndicator;
[SerializeField] private GameObject chatWindowObject; // 대화 종료용
private Coroutine _typingCoroutine;
private Coroutine _clickCoroutine;
private string _inputText;
private Queue<DialogueStruct> _inputQueue;
public delegate void OnComplete();
public OnComplete onComplete;
private bool isEnded;
private bool isTuto;
private FairyDialogueManager _dialogueManager;
private void Awake()
{
_inputQueue = new Queue<DialogueStruct>();
chatWindowObject.SetActive(false); // 일단 비활성화로 시작
}
private void Start()
{
isEnded = false;
isTuto = false;
_dialogueManager = new FairyDialogueManager(this);
onComplete = () =>
{
GameManager.Instance.gotoBed = true;
};
onComplete = () => {
if (isTuto)
{
isTuto = false;
StartCoroutine(GameManager.Instance.StartTutorialCoroutine());
}
if (isEnded)
GameManager.Instance.ChangeToMainScene();
};
}
// 외부 호출용 함수 (대화 시작)
public void SetGamePhase(GamePhase phase)
{
_dialogueManager.SetGamePhase(phase);
if (phase == GamePhase.End || phase == GamePhase.FailEnd || phase == GamePhase.ZeroEnd)
isEnded = true;
if (phase == GamePhase.Intro)
isTuto = true;
// Gameplay 상태라면 랜덤 대화 출력
if (phase == GamePhase.Gameplay) _dialogueManager.ShowRandomGameplayDialogue();
}
#region Show and Hide
// 대화창 표시
public void ShowWindow()
{
chatWindowObject.SetActive(true);
if (_inputQueue.Count > 0)
{
ShowNextDialogue();
PlayerStats.Instance.HideBubble();
}
}
// 대화창 숨기기
public void HideWindow()
{
chatWindowObject.SetActive(false);
onComplete?.Invoke(); // 대화창 중지하며 콜백 호출
// 진행 중인 모든 코루틴 중지
if (_typingCoroutine != null)
{
StopCoroutine(_typingCoroutine);
_typingCoroutine = null;
}
if (_clickCoroutine != null)
{
StopCoroutine(_clickCoroutine);
_clickCoroutine = null;
}
PlayerStats.Instance.ShowBubble();
}
#endregion
// 대화 시퀀스 설정
public void SetDialogueSequence(List<DialogueStruct> sequence)
{
// 기존 큐 초기화
_inputQueue.Clear();
// 새 대화 시퀀스를 큐에 추가
foreach (DialogueStruct dialog in sequence)
{
_inputQueue.Enqueue(dialog);
}
}
// 다음 대화 표시
private void ShowNextDialogue()
{
if (_inputQueue.Count == 0)
{
HideWindow();
return;
}
DialogueStruct dialog = _inputQueue.Dequeue();
// 이름 텍스트 업데이트
if (nameText != null)
{
nameText.text = dialog.name;
}
// 클릭 인디케이터 활성화
var clickIndicatorColor = clickIndicator.color;
clickIndicatorColor.a = 1;
clickIndicator.color = clickIndicatorColor;
_inputText = dialog.text;
// 이전 타이핑 코루틴 중단
if (_typingCoroutine != null)
{
StopCoroutine(_typingCoroutine);
}
// 새 타이핑 코루틴 시작
_typingCoroutine = StartCoroutine(TypingEffectCoroutine(_inputText));
}
//텍스트 타이핑효과 코루틴
private IEnumerator TypingEffectCoroutine(string text)
{
StringBuilder strText = new StringBuilder();
for (int i = 0; i < text.Length; i++)
{
strText.Append(text[i]);
chatText.text = strText.ToString();
yield return new WaitForSeconds(0.05f);
GameManager.Instance.PlayTypingSound();
}
_clickCoroutine = StartCoroutine(ClickIndicatorCoroutine());
_typingCoroutine = null;
}
private IEnumerator ClickIndicatorCoroutine()
{
bool flag = true;
var clickIndicatorColor = clickIndicator.color;
while (true)
{
clickIndicatorColor.a = flag? 0:1;
flag = !flag;
clickIndicator.color = clickIndicatorColor;
yield return new WaitForSeconds(0.5f);
}
}
//대화창 클릭 시 호출 함수
public void OnPointerClick(PointerEventData eventData)
{
if (!chatWindowObject.activeSelf) // 실제론 대화창이 off 상태인데 호출되는 상황 방지
return;
if (_typingCoroutine != null)
{
StopCoroutine(_typingCoroutine);
_typingCoroutine = null;
if (chatText != null) chatText.text = _inputText;
if (clickIndicator != null) _clickCoroutine = StartCoroutine(ClickIndicatorCoroutine());
}
else
{
if (_clickCoroutine != null)
{
StopCoroutine(_clickCoroutine);
_clickCoroutine = null;
}
if (_inputQueue.Count > 0) // 대화가 남은 경우
{
ShowNextDialogue();
}
else
{
HideWindow(); // 대화 종료되면 창 닫기
}
}
}
}