using System.Collections; using UnityEngine; using UnityEngine.Networking; public class NPCDialogueManager : MonoBehaviour { [Header("UI 연결")] public GameObject dialoguePanel; // 대화창 배경 패널 public TMPro.TextMeshProUGUI dialogueText; // 대사 텍스트 TMP 컴포넌트 private string lastDialogueText = "대화 버튼을 눌러 조언을 얻으세요."; private string targetDialogueText = ""; // 목표 대사 텍스트 private Coroutine typingCoroutine; // 타이핑 코루틴 제어용 // JSON 파싱용 Dialogue 응답 매핑 클래스 (스코프 오류 방지를 위해 내부 클래스로 내장) [System.Serializable] public class DialogueResponse { public string dialogue; } private void Start() { // 시작 시 대화 패널을 비활성화해 둡니다. if (dialoguePanel != null) { dialoguePanel.SetActive(false); } } // NPC 대화를 요청하는 메서드 public void RequestNPCDialogue(int currentGeneration) { StartCoroutine(FetchNPCDialogue(currentGeneration)); } // NPC 영역을 벗어났을 때 대화창을 명시적으로 닫는 메서드 public void CloseDialogue() { if (typingCoroutine != null) { StopCoroutine(typingCoroutine); typingCoroutine = null; } if (dialoguePanel != null) { dialoguePanel.SetActive(false); // 대화 배경 끄기 } } private IEnumerator FetchNPCDialogue(int currentGeneration) { // 1. 대화 패널 활성화 및 대기 연출 문구 노출 if (dialoguePanel != null) { dialoguePanel.SetActive(true); } if (typingCoroutine != null) { StopCoroutine(typingCoroutine); } lastDialogueText = "늙은 문지기 발두르가 눈을 지그시 감고 네 선조들의 최후를 떠올리는 중입니다..."; if (dialogueText != null) { dialogueText.text = lastDialogueText; } // FastAPI의 NPC 대화 조회 엔드포인트 URL 구성 string url = $"http://192.168.1.7:8000/api/game/npc-dialogue?current_generation={currentGeneration}"; Debug.Log($"[Dialogue] NPC 대사 조회 요청 전송: {url}"); using (UnityWebRequest request = UnityWebRequest.Get(url)) { yield return request.SendWebRequest(); if (request.result == UnityWebRequest.Result.ConnectionError || request.result == UnityWebRequest.Result.ProtocolError) { Debug.LogError($"[Dialogue] NPC 대사 조회 실패: {request.error}"); lastDialogueText = "문지기 발두르가 침묵하고 있습니다. (서버 연결 실패)"; if (dialogueText != null) { dialogueText.text = lastDialogueText; } } else { try { string json = request.downloadHandler.text; DialogueResponse response = JsonUtility.FromJson(json); targetDialogueText = response.dialogue; Debug.Log($"[Dialogue] 문지기 대사 수신 성공:\n{targetDialogueText}"); // 2. 타자기 연출(Typewriter) 코루틴 시작 typingCoroutine = StartCoroutine(TypeTextEffect(targetDialogueText)); } catch (System.Exception ex) { Debug.LogError($"[Dialogue] JSON 파싱 에러: {ex.Message}"); lastDialogueText = "문지기의 말을 이해할 수 없습니다. (데이터 파싱 오류)"; if (dialogueText != null) { dialogueText.text = lastDialogueText; } } } } } // 한 글자씩 부드럽게 출력해주는 타자기 효과 코루틴 private IEnumerator TypeTextEffect(string fullText) { lastDialogueText = ""; float letterDelay = 0.04f; foreach (char letter in fullText.ToCharArray()) { lastDialogueText += letter; // 텍스트 UI 컴포넌트 갱신 if (dialogueText != null) { dialogueText.text = lastDialogueText; } // 공백 문자가 아닌 경우에만 츤데레 훈수 타자기 효과음 재생 if (letter != ' ' && SoundManager.Instance != null) { SoundManager.Instance.PlayTyping(); } // 쉼표(,)나 마침표(.) 등 문장이 끊기는 지점에서는 살짝 더 더듬는 효과(딜레이 추가) 제공 if (letter == ',' || letter == '.') { yield return new WaitForSeconds(letterDelay * 4f); } else { yield return new WaitForSeconds(letterDelay); } } typingCoroutine = null; } }