DEG-118 [Feat] GameManager에 대화창 접근 메서드 추가

This commit is contained in:
Sehyeon 2025-04-30 14:15:30 +09:00
parent 57419f5c01
commit a61f52fb10
9 changed files with 242 additions and 186 deletions

BIN
Assets/KSH/DungeonTestScene.unity (Stored with Git LFS)

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@ -73,9 +73,9 @@ Material:
- _OutlineWidth: 0
- _PerspectiveFilter: 0.875
- _Reflectivity: 10
- _ScaleRatioA: 1
- _ScaleRatioB: 1
- _ScaleRatioC: 1
- _ScaleRatioA: 0.8333333
- _ScaleRatioB: 0.6770833
- _ScaleRatioC: 0.6770833
- _ScaleX: 1
- _ScaleY: 1
- _ShaderFlags: 0
@ -120,9 +120,9 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 71c1514a6bd24e1e882cebbe1904ce04, type: 3}
m_Name: Galmuri9 SecondNew SDF
m_EditorClassIdentifier:
hashCode: 0
hashCode: -1168553587
material: {fileID: -8204146546353023211}
materialHashCode: 0
materialHashCode: 851507981
m_Version: 1.1.0
m_SourceFontFileGUID: 9ff625240d1af4e419ba1a029337b761
m_SourceFontFile_EditorRef: {fileID: 12800000, guid: 9ff625240d1af4e419ba1a029337b761,

View File

@ -80,14 +80,7 @@
{
"id": "player_gameplay_3",
"name": "주인공",
"text": "한다면... 설마 부와 명예를?",
"nextId": "fairy_gameplay_4",
"phase": "gameplay"
},
{
"id": "fairy_gameplay_4",
"name": "냉장고 요정",
"text": "축하의 박수를 쳐줄게~",
"text": "한다면... 뭐지?",
"nextId": "",
"phase": "gameplay"
},
@ -150,7 +143,7 @@
{
"id": "fairy_end_5",
"name": "냉장고 요정",
"text": "... 엔딩 크레딧 출력!",
"text": "... GameManager.Instance.ShowCredit(GamePhase.End);",
"nextId": "",
"phase": "end"
}

View File

@ -44,6 +44,7 @@ public class ChatWindowController : MonoBehaviour, IPointerClickHandler
[SerializeField] private TMP_Text chatText;
[SerializeField] private Image clickIndicator;
[SerializeField] private GameObject chatWindowObject; // 대화 종료용
[SerializeField] private AudioClip typingClip; // 타이핑 사운드
private Coroutine _typingCoroutine;
private Coroutine _clickCoroutine;
@ -53,8 +54,6 @@ public class ChatWindowController : MonoBehaviour, IPointerClickHandler
public delegate void OnComplete();
public OnComplete onComplete;
private bool _dialogueEnded = false; // 대화 종료 여부
private FairyDialogueManager _dialogueManager;
private void Awake()
@ -65,48 +64,29 @@ public class ChatWindowController : MonoBehaviour, IPointerClickHandler
private void Start()
{
// FairyDialogueManager 초기화
_dialogueManager = new FairyDialogueManager(this);
// 완료 콜백 설정
onComplete = () => {
// 대화문 종료 call back
Debug.Log("대화가 완료되었습니다.");
};
// 테스트 코드: 인트로 대화 시작
Debug.Log("인트로 대화 시작");
_dialogueManager.SetGamePhase(GamePhase.Intro);
// 테스트 코드: 게임플레이 및 엔딩 대화 테스트를 위한 코루틴 시작
StartCoroutine(TestDialogueSequence());
}
// 테스트 코드
private IEnumerator TestDialogueSequence()
// 외부 호출용 함수 (대화 시작)
public void SetGamePhase(GamePhase phase)
{
// 인트로 대화가 끝날 시간을 대략적으로 기다림
yield return new WaitForSeconds(5f);
// 게임플레이 단계로 전환
Debug.Log("게임플레이 대화 시작");
_dialogueManager.SetGamePhase(GamePhase.Gameplay);
_dialogueManager.TalkToFairy();
// 3초 후 다른 게임플레이 대화 테스트
yield return new WaitForSeconds(3f);
_dialogueManager.StartDialogueById("fairy_gameplay_2");
// 3초 후 엔딩 대화 테스트
yield return new WaitForSeconds(3f);
Debug.Log("엔딩 대화 시작");
_dialogueManager.SetGamePhase(GamePhase.End);
_dialogueManager.SetGamePhase(phase);
// Gameplay 상태라면 랜덤 대화 출력
if (phase == GamePhase.Gameplay) _dialogueManager.ShowRandomGameplayDialogue();
}
#region Show and Hide
// 대화창 표시
public void ShowWindow()
{
chatWindowObject.SetActive(true);
_dialogueEnded = false;
if (_inputQueue.Count > 0)
{
@ -134,12 +114,13 @@ public class ChatWindowController : MonoBehaviour, IPointerClickHandler
}
}
#endregion
// 대화 시퀀스 설정
public void SetDialogueSequence(List<DialogueStruct> sequence)
{
// 기존 큐 초기화
_inputQueue.Clear();
_dialogueEnded = false;
// 새 대화 시퀀스를 큐에 추가
foreach (DialogueStruct dialog in sequence)
@ -153,7 +134,8 @@ public class ChatWindowController : MonoBehaviour, IPointerClickHandler
{
if (_inputQueue.Count == 0)
{
_dialogueEnded = true;
HideWindow();
onComplete?.Invoke();
return;
}
@ -191,6 +173,7 @@ public class ChatWindowController : MonoBehaviour, IPointerClickHandler
strText.Append(text[i]);
chatText.text = strText.ToString();
yield return new WaitForSeconds(0.05f);
SoundManager.Instance.PlaySFX(typingClip); // 타이핑 사운드
}
_clickCoroutine = StartCoroutine(ClickIndicatorCoroutine());
@ -217,8 +200,8 @@ public class ChatWindowController : MonoBehaviour, IPointerClickHandler
{
StopCoroutine(_typingCoroutine);
_typingCoroutine = null;
chatText.text = _inputText;
_clickCoroutine = StartCoroutine(ClickIndicatorCoroutine());
if (chatText != null) chatText.text = _inputText;
if (clickIndicator != null) _clickCoroutine = StartCoroutine(ClickIndicatorCoroutine());
}
else
{
@ -228,23 +211,14 @@ public class ChatWindowController : MonoBehaviour, IPointerClickHandler
_clickCoroutine = null;
}
// 대화가 끝났으면 창 닫기
if (_dialogueEnded)
{
HideWindow();
onComplete?.Invoke();
return;
}
if (_inputQueue.Count > 0) // 대화가 남은 경우
{
ShowNextDialogue();
}
else
{
_dialogueEnded = true; // 일단 대화창 닫고 이후 콜백 호출
HideWindow(); // 대화 종료되면 창 닫기
}
}
}
}

View File

@ -4,25 +4,22 @@ using System.Linq;
using UnityEngine;
using Random = UnityEngine.Random;
// 일반 클래스로 변경된 FairyDialogueManager
public class FairyDialogueManager
{
private ChatWindowController _chatWindow;
private string _dialogueFileName;
// 현재 게임 단계
private GamePhase _currentGamePhase = GamePhase.Intro;
private GamePhase _currentGamePhase = GamePhase.Intro; // 현재 게임 단계
private DialogueData _database;
private Dictionary<string, DialogueStruct> _dialogueDict;
// 단계별 대화 모음
private Dictionary<string, List<DialogueStruct>> _phaseDialogues;
// 이미 보여준 게임플레이 대화 추적
private HashSet<string> _shownGameplayDialogueIds;
private string _fairyName = "냉장고 요정";
// 생성자
public FairyDialogueManager(ChatWindowController chatWindow, string dialogueFileName = "dialogue.json")
{
_chatWindow = chatWindow;
@ -41,33 +38,15 @@ public class FairyDialogueManager
if (jsonFile == null)
{
Debug.LogError($"Failed to load dialogue database: {filePath}");
Debug.LogError($"경로 오류로 인한 대화 데이터 로딩 실패 : {filePath}");
_database = new DialogueData { dialogues = new List<DialogueStruct>() };
return;
}
Debug.Log($"JSON 파일 내용: {jsonFile.text.Substring(0, Mathf.Min(200, jsonFile.text.Length))}..."); // 파일 내용 확인
try {
_database = JsonUtility.FromJson<DialogueData>(jsonFile.text);
Debug.Log($"대화 항목 수: {_database.dialogues.Count}");
// 검증: 각 단계별 대화 항목 수 확인
Dictionary<string, int> phaseCount = new Dictionary<string, int>();
foreach (var dialogue in _database.dialogues)
{
if (!phaseCount.ContainsKey(dialogue.phase))
phaseCount[dialogue.phase] = 0;
phaseCount[dialogue.phase]++;
}
foreach (var phase in phaseCount)
{
Debug.Log($"단계 '{phase.Key}': {phase.Value}개 항목");
}
// 대화 사전 초기화
_dialogueDict = new Dictionary<string, DialogueStruct>();
_dialogueDict = new Dictionary<string, DialogueStruct>(); // 대화 사전 초기화
foreach (DialogueStruct entry in _database.dialogues)
{
_dialogueDict[entry.id] = entry;
@ -95,12 +74,11 @@ public class FairyDialogueManager
}
}
// 게임 단계 설정
// 게임 단계 설정, GamePlay는 따로 실행
public void SetGamePhase(GamePhase phase)
{
_currentGamePhase = phase;
// Intro 또는 End 단계로 진입 시 자동으로 해당 대화 시작
if (phase == GamePhase.Intro)
{
StartPhaseDialogue("intro");
@ -120,13 +98,12 @@ public class FairyDialogueManager
return;
}
// 해당 단계의 첫 대화 항목 찾기 (요정이 먼저 말하는 대화)
// 첫 대화 찾기 (요정이 먼저 말함)
DialogueStruct startEntry = _phaseDialogues[phaseName]
.FirstOrDefault(d => d.name == "냉장고 요정" && !string.IsNullOrEmpty(d.nextId));
.FirstOrDefault(d => d.name == _fairyName && !string.IsNullOrEmpty(d.nextId));
if (startEntry == null)
{
// 적합한 시작 대화가 없으면 첫 번째 대화 사용
startEntry = _phaseDialogues[phaseName][0];
}
@ -134,18 +111,14 @@ public class FairyDialogueManager
StartDialogueSequence(startEntry.id);
}
// 랜덤 게임플레이 대화 보여주기
// Gameplay일 때 랜덤 대화 출력
public void ShowRandomGameplayDialogue()
{
if (_currentGamePhase != GamePhase.Gameplay)
{
Debug.LogWarning("Random dialogue can only be shown during gameplay phase");
return;
}
if (_currentGamePhase != GamePhase.Gameplay) return;
// 게임플레이 단계의 요정 대화 중 아직 보여주지 않은 것 찾기
// 요정 대화 중 아직 보여주지 않은 것 찾기
var availableDialogues = _phaseDialogues["gameplay"]
.Where(d => d.name == "냉장고 요정" && !_shownGameplayDialogueIds.Contains(d.id))
.Where(d => d.name == _fairyName && !_shownGameplayDialogueIds.Contains(d.id))
.ToList();
// 모든 대화를 다 보여줬다면 다시 초기화
@ -153,7 +126,7 @@ public class FairyDialogueManager
{
_shownGameplayDialogueIds.Clear();
availableDialogues = _phaseDialogues["gameplay"]
.Where(d => d.name == "냉장고 요정")
.Where(d => d.name == _fairyName)
.ToList();
}
@ -174,17 +147,11 @@ public class FairyDialogueManager
// 대화 ID로 대화 시작
public void StartDialogueSequence(string startDialogueId)
{
if (!_dialogueDict.ContainsKey(startDialogueId))
{
Debug.LogError($"Dialogue ID not found: {startDialogueId}");
return;
}
if (!_dialogueDict.ContainsKey(startDialogueId)) return;
// 시작 대화 항목 가져오기
DialogueStruct startEntry = _dialogueDict[startDialogueId];
DialogueStruct startEntry = _dialogueDict[startDialogueId]; // 시작 대화
// 대화 시퀀스 구성
List<DialogueStruct> sequence = BuildDialogueSequence(startEntry);
List<DialogueStruct> sequence = BuildDialogueSequence(startEntry); // 대화 시퀀스 구성
// 대화창에 대화 시퀀스 전달
_chatWindow.SetDialogueSequence(sequence);
@ -217,24 +184,7 @@ public class FairyDialogueManager
return sequence;
}
// 요정에게 말 걸기 (게임 중 언제든 사용 가능)
public void TalkToFairy()
{
switch (_currentGamePhase)
{
case GamePhase.Intro:
StartPhaseDialogue("intro");
break;
case GamePhase.Gameplay:
ShowRandomGameplayDialogue();
break;
case GamePhase.End:
StartPhaseDialogue("end");
break;
}
}
// 특정 대화 ID로 대화 시작 (외부에서 호출 가능)
// 특정 대화 ID로 대화 시작 (세이브/로드 시 사용)
public void StartDialogueById(string dialogueId)
{
if (_dialogueDict.ContainsKey(dialogueId))
@ -246,10 +196,4 @@ public class FairyDialogueManager
Debug.LogError($"Dialogue ID not found: {dialogueId}");
}
}
// 완료 콜백 설정
public void SetOnCompleteCallback(ChatWindowController.OnComplete callback)
{
_chatWindow.onComplete = callback;
}
}

View File

@ -21,6 +21,8 @@ public partial class GameManager : Singleton<GameManager>
// 날짜 변경 이벤트, 추후에 UI 상의 날짜를 변경할 때 사용
public event Action<int> OnDayChanged;
private ChatWindowController chatWindowController; // 대화창 컨트롤러
private void Start()
{
// 오디오 초기화
@ -39,6 +41,23 @@ public partial class GameManager : Singleton<GameManager>
}
playerStats.OnDayEnded += AdvanceDay;
}
#region
public void StartNPCDialogue(GamePhase phase) // intro, gameplay, end 존재
{
if(chatWindowController == null)
SetChatWindowController();
chatWindowController.SetGamePhase(phase);
}
private void SetChatWindowController()
{
chatWindowController = FindObjectOfType<ChatWindowController>();
}
#endregion
// 날짜 진행
public void AdvanceDay()

View File

@ -10,7 +10,7 @@ public enum EndingType
Happy // 던전 공략 O, 평판 기본 스탯 값 * 1.5 이상
}
public partial class GameManager : Singleton<GameManager>
public partial class GameManager
{
private float happyEndReputation = 3.0f;
@ -23,6 +23,9 @@ public partial class GameManager : Singleton<GameManager>
// 엔딩 관련 메서드. 7일차에 실행
private void TriggerTimeEnding()
{
// npc와의 마지막 대화 출력
StartNPCDialogue(GamePhase.End);
// 플레이어 상태에 따라 엔딩 판별
EndingType endingType = DetermineEnding();

View File

@ -3,7 +3,7 @@ using System.Collections;
using System.Collections.Generic;
// 게임 매니저의 오디오 관련 부분 클래스
public partial class GameManager : Singleton<GameManager>
public partial class GameManager
{
// 오디오 클립 참조
[Header("오디오 설정")]