콜라이더 충돌 시 npc 대사 출력 기능 구현 및 HP 바 기능 구현
This commit is contained in:
@@ -4,9 +4,29 @@ 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; // 타이핑 코루틴 제어용
|
||||
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)
|
||||
@@ -14,14 +34,39 @@ public class NPCDialogueManager : MonoBehaviour
|
||||
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. 대기 연출: 요청 즉시 로딩중 텍스트를 띄워 렉처럼 보이지 않게 합니다.
|
||||
// 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://127.0.0.1:8000/api/game/npc-dialogue?current_generation={currentGeneration}";
|
||||
@@ -36,6 +81,10 @@ public class NPCDialogueManager : MonoBehaviour
|
||||
{
|
||||
Debug.LogError($"[Dialogue] NPC 대사 조회 실패: {request.error}");
|
||||
lastDialogueText = "문지기 발두르가 침묵하고 있습니다. (서버 연결 실패)";
|
||||
if (dialogueText != null)
|
||||
{
|
||||
dialogueText.text = lastDialogueText;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -54,6 +103,10 @@ public class NPCDialogueManager : MonoBehaviour
|
||||
{
|
||||
Debug.LogError($"[Dialogue] JSON 파싱 에러: {ex.Message}");
|
||||
lastDialogueText = "문지기의 말을 이해할 수 없습니다. (데이터 파싱 오류)";
|
||||
if (dialogueText != null)
|
||||
{
|
||||
dialogueText.text = lastDialogueText;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -63,13 +116,18 @@ public class NPCDialogueManager : MonoBehaviour
|
||||
private IEnumerator TypeTextEffect(string fullText)
|
||||
{
|
||||
lastDialogueText = "";
|
||||
// 문지기가 고민하면서 한 글자씩 읊조리는 속도 (0.04초 간격)
|
||||
float letterDelay = 0.04f;
|
||||
|
||||
foreach (char letter in fullText.ToCharArray())
|
||||
{
|
||||
lastDialogueText += letter;
|
||||
|
||||
// 텍스트 UI 컴포넌트 갱신
|
||||
if (dialogueText != null)
|
||||
{
|
||||
dialogueText.text = lastDialogueText;
|
||||
}
|
||||
|
||||
// 쉼표(,)나 마침표(.) 등 문장이 끊기는 지점에서는 살짝 더 더듬는 효과(딜레이 추가) 제공
|
||||
if (letter == ',' || letter == '.')
|
||||
{
|
||||
@@ -83,15 +141,13 @@ public class NPCDialogueManager : MonoBehaviour
|
||||
typingCoroutine = null;
|
||||
}
|
||||
|
||||
// 디버그용 임시 GUI 버튼 및 대사 출력창
|
||||
// 디버그용 임시 OnGUI 버튼
|
||||
private void OnGUI()
|
||||
{
|
||||
GUI.backgroundColor = Color.yellow;
|
||||
|
||||
// NPC 대화 요청 버튼 (화면 우측 상단 배치)
|
||||
if (GUI.Button(new Rect(Screen.width - 240, 10, 220, 50), "Debug: Get NPC Dialogue"))
|
||||
{
|
||||
// 플레이어 오브젝트를 찾아 현재 세대 값을 가져옵니다.
|
||||
Player player = FindObjectOfType<Player>();
|
||||
if (player != null)
|
||||
{
|
||||
@@ -103,21 +159,16 @@ public class NPCDialogueManager : MonoBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
// 대사 출력 박스 배경 및 텍스트 렌더링
|
||||
GUI.color = Color.white;
|
||||
GUI.Box(new Rect(Screen.width - 450, 70, 430, 120), "늙은 문지기 '발두르'의 조언");
|
||||
|
||||
GUIStyle dialogueStyle = new GUIStyle(GUI.skin.label);
|
||||
dialogueStyle.wordWrap = true;
|
||||
dialogueStyle.fontSize = 14;
|
||||
|
||||
GUI.Label(new Rect(Screen.width - 440, 95, 410, 90), lastDialogueText, dialogueStyle);
|
||||
if (dialoguePanel != null && dialoguePanel.activeSelf)
|
||||
{
|
||||
GUI.color = Color.white;
|
||||
GUI.Box(new Rect(Screen.width - 450, 70, 430, 120), "늙은 문지기 '발두르'의 조언 (Debug)");
|
||||
|
||||
GUIStyle dialogueStyle = new GUIStyle(GUI.skin.label);
|
||||
dialogueStyle.wordWrap = true;
|
||||
dialogueStyle.fontSize = 14;
|
||||
|
||||
GUI.Label(new Rect(Screen.width - 440, 95, 410, 90), lastDialogueText, dialogueStyle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// JSON 파싱용 Dialogue 응답 매핑 클래스
|
||||
[System.Serializable]
|
||||
public class DialogueResponse
|
||||
{
|
||||
public string dialogue;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
using UnityEngine;
|
||||
|
||||
[RequireComponent(typeof(Collider2D))] // 감지를 위한 Collider2D(Trigger 설정)가 필수적으로 요구됩니다.
|
||||
public class NPCInteraction : MonoBehaviour
|
||||
{
|
||||
private NPCDialogueManager dialogueManager;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
// 1. 씬에 배치된 NPCDialogueManager 컴포넌트를 탐색해 바인딩합니다.
|
||||
dialogueManager = FindObjectOfType<NPCDialogueManager>();
|
||||
if (dialogueManager == null)
|
||||
{
|
||||
Debug.LogError("[NPC] 씬에서 NPCDialogueManager를 찾을 수 없습니다! DialogueManager 오브젝트가 배치되어 있는지 확인하세요.");
|
||||
}
|
||||
|
||||
// 2. 부착된 콜라이더가 트리거(Trigger)로 체크되어 있지 않다면 강제로 설정하여 물리 막힘 현상을 배제합니다.
|
||||
Collider2D col = GetComponent<Collider2D>();
|
||||
if (col != null && !col.isTrigger)
|
||||
{
|
||||
col.isTrigger = true;
|
||||
Debug.LogWarning($"[NPC] {gameObject.name}에 부착된 Collider2D의 'Is Trigger' 속성을 자동으로 켰습니다.");
|
||||
}
|
||||
}
|
||||
|
||||
// 플레이어가 NPC의 감지 반경(Trigger Collider) 내부로 들어왔을 때 실행
|
||||
private void OnTriggerEnter2D(Collider2D other)
|
||||
{
|
||||
// 충돌한 오브젝트가 플레이어인지 검사합니다.
|
||||
Player player = other.GetComponent<Player>();
|
||||
if (player != null)
|
||||
{
|
||||
if (dialogueManager != null)
|
||||
{
|
||||
Debug.Log($"[NPC] 플레이어({player.CharacterName})가 가까이 왔습니다. 세대({player.Generation}대) 조언을 요청합니다.");
|
||||
dialogueManager.RequestNPCDialogue(player.Generation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 플레이어가 NPC의 감지 반경을 벗어났을 때 실행
|
||||
private void OnTriggerExit2D(Collider2D other)
|
||||
{
|
||||
Player player = other.GetComponent<Player>();
|
||||
if (player != null)
|
||||
{
|
||||
if (dialogueManager != null)
|
||||
{
|
||||
Debug.Log("[NPC] 플레이어가 멀어졌습니다. 대화창을 닫습니다.");
|
||||
dialogueManager.CloseDialogue();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 531f5ebc513124b65ab6db8bdff1d091
|
||||
@@ -1,4 +1,6 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TMPro;
|
||||
|
||||
public struct Inputs
|
||||
{
|
||||
@@ -29,7 +31,7 @@ public class Player : MonoBehaviour
|
||||
// 이동 관련 변수
|
||||
[SerializeField] private float speed = 5f;
|
||||
[SerializeField] public int hp = 5;
|
||||
private int maxHp;
|
||||
[SerializeField] public int maxHp = 5;
|
||||
|
||||
private bool isFacingRight = false;
|
||||
private int currentAnimationState = -1;
|
||||
@@ -43,6 +45,10 @@ public class Player : MonoBehaviour
|
||||
public int Generation => generation;
|
||||
public string CharacterName => characterName;
|
||||
|
||||
[Header("UI 연결")]
|
||||
public TextMeshProUGUI nameText;
|
||||
public Image hpImage;
|
||||
|
||||
private static readonly string[] RANDOM_NAMES = new string[]
|
||||
{
|
||||
"자르반", "가렌", "럭스", "다리우스", "야스오", "티모", "아리", "이즈리얼",
|
||||
@@ -80,6 +86,22 @@ public class Player : MonoBehaviour
|
||||
|
||||
private void Update()
|
||||
{
|
||||
// 안전 조치: maxHp가 비정상(0 이하)이거나 현재 체력이 초과된 경우 자동 동기화
|
||||
if (maxHp <= 0 || hp > maxHp)
|
||||
{
|
||||
maxHp = hp;
|
||||
}
|
||||
|
||||
if (hpImage != null && maxHp > 0)
|
||||
{
|
||||
float fillRatio = Mathf.Clamp01((float)hp / maxHp);
|
||||
hpImage.fillAmount = fillRatio;
|
||||
|
||||
// 이미지 컴포넌트의 타입(Simple, Filled 등)과 상관없이 무조건 가로 크기가 깎이도록
|
||||
// RectTransform의 로컬 스케일 X축도 비율에 맞춰 실시간으로 동기화합니다.
|
||||
hpImage.rectTransform.localScale = new Vector3(fillRatio, 1f, 1f);
|
||||
}
|
||||
|
||||
if (hp <= 0)
|
||||
{
|
||||
if (animator != null)
|
||||
@@ -256,6 +278,10 @@ public class Player : MonoBehaviour
|
||||
// 이름 랜덤 선택 후 세대 접미사 추가 (예: 자르반 3세)
|
||||
string baseName = RANDOM_NAMES[Random.Range(0, RANDOM_NAMES.Length)];
|
||||
characterName = $"{baseName} {generation}세";
|
||||
if (nameText != null)
|
||||
{
|
||||
nameText.text = characterName;
|
||||
}
|
||||
Debug.Log($"캐릭터 생성 완료! 이름: {characterName}, 세대: {generation}대");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user