오늘은 대화창의 선택에 따라 퀘스트가 진행되도록 만들어보자 

우선 퀘스트를 하나 만들어줘야한다. 퀘스트는 Scriptable Object로 만들어서 관리해주도록 하자. 

클래스위에 Create를 쉽게 할 수 있도록 메뉴에서 선택가능하도록 메뉴에 추가해주는 코드를 추가해줬다.

QuestData.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu(fileName = "NewQuest", menuName = "Quest/QuestData")]
public class QuestData : ScriptableObject
{
    [Header("Quest Info")]
    public string questName;
    public int questId;             //퀘스트번호
    public QuestState questState;   //퀘스트 상태
    public int QuestIndex;          //퀘스트 필요인덱스
    public string location;

    [Header("Reward Info")]
    public int goldReward;
}

 

이 QuestData를 관리해주는 Manager를 만들어주자. 퀘스트를 Resource에서 가져오고 Quest의 상태를 Update하고 QuestData를 반환해주는 함수도 추가해주자.

QuestManager.cs

using System.Collections.Generic;
using UnityEngine;

public class QuestManager : MonoBehaviour
{
    [SerializeField] private Dictionary<int, QuestData> Quests;

    public void Init()
    {
        LoadQuestsFromResources();
        InitializeQuest();
    }

    // Resources 폴더에서 모든 ScriptableObject를 로드하고 Dictionary로 초기화
    private void LoadQuestsFromResources()
    {
        QuestData[] loadedQuests = Resources.LoadAll<QuestData>("Quest");
        Quests = new Dictionary<int, QuestData>();
        if (loadedQuests.Length == 0)
        {
            Debug.LogError("Resources/Quest 폴더에 퀘스트 데이터가 없습니다.");
            return;
        }

        foreach (QuestData questData in loadedQuests)
        {
            if (!Quests.ContainsKey(questData.questId))
            {
                Quests.Add(questData.questId, questData);
                Debug.Log($"퀘스트 Id '{questData.questId}' 인 '{questData.questName}'가 추가되었습니다.");
            }
            else
            {
                Debug.LogWarning($"중복된 questId({questData.questId})가 발견되었습니다. QuestName: {questData.questName}");
            }
        }

        Debug.Log($"{Quests.Count}개의 퀘스트가 로드되었습니다.");
    }

    // Dictionary를 사용하여 퀘스트를 초기화
    private void InitializeQuest()
    {
        if (Quests == null || Quests.Count == 0)
        {
            Debug.LogError("Quests가 null이거나 비어 있습니다. LoadQuestsFromResources를 확인하세요.");
            return;
        }

        foreach (var questData in Quests.Values)
        {
            if (questData.QuestIndex >= Managers.Game.GetPlayer().GetComponent<Player>().index &&
                questData.questState == QuestState.REQUIREMENTS_NOT_MET)
            {
                // 진행 가능한 상태로 변경
                questData.questState = QuestState.CAN_START;
                Debug.Log($"퀘스트 Id '{questData.questId}' 인 '{questData.questName}'가 CAN_START로 초기화되었습니다.");
            }
        }
    }

    // 퀘스트 상태를 업데이트
    public void UpdateQuest(int questId)
    {
        if (Quests.TryGetValue(questId, out QuestData questData))
        {
            questData.questState++;

            if (questData.questState == QuestState.CAN_START)
            {
                Debug.Log($"퀘스트 시작! QuestName: {questData.questName}");
            }
            else if (questData.questState == QuestState.CAN_FINISH)
            {
                Debug.Log($"퀘스트 완료 가능! QuestName: {questData.questName}");
            }
            else if (questData.questState == QuestState.FINISHED)
            {
                Debug.Log($"퀘스트 완료! QuestName: {questData.questName}");
                Managers.Game.GetPlayer().GetComponent<Player>().index++;
                InitializeQuest();
            }
        }
        else
        {
            Debug.LogError($"questId({questId})에 해당하는 퀘스트가 없습니다.");
        }
    }

    // questId로 퀘스트 데이터를 가져옴
    public QuestData GetQuestData(int questId)
    {
        foreach (var questData in Quests.Values)
        {
            Debug.Log(questData.name);
            if (questData.questId == questId) return questData;
        }

        return null;
    }
}

 

이렇게 해주고 간단한 퀘스트를 추가해서 이 매니저가 작동하는지 확인해주자

우선 퀘스트를 가져오는 것은 성공했다.

이제 대화에서 선택했을 때 퀘스트의 진행상황이 바뀌는지 확인하자. 이를 위해 DialogueManager의 Tag관리 코드를 수정해주자.

DialogueManager.cs

private const string QuestTag = "Quest"; //테그값들 테그값 : 변수
private const string ChooseTag = "Start";
private const string EndTag = "End";

public void ContinueStory()
{
    if (currentStory == null) // Null 체크 추가
    {
        Debug.LogError("currentStory가 null입니다!");
        return;
    }

    if (currentStory.canContinue) // 더 보여줄 이야기가 있다면
    {
        popup.displayNameText.text = npcdata.getName();
        popup.portraitImage.sprite = npcdata.getPortrait();
        popup.dialogueText.text = currentStory.Continue(); // 한줄 출력
        DisplayChoices(); // 선택이 있으면 선택 출력
        HandleTags(currentStory.currentTags);
    }
    else
    {
        ExitDialogueMode();
    }
}
 
 private void HandleTags(List<string> currentTags)
 {
     foreach (string tag in currentTags)
     {
         string[] splitTag = tag.Split(':');
         if (splitTag.Length != 2)
         {
             Debug.LogError("Tag parsed error : " + tag + splitTag);
         }
         string tagkey = splitTag[0].Trim();
         string tagvalue = splitTag[1].Trim();


         switch (tagkey)
         {
             case QuestTag:
                 currentQuestIndex = int.Parse(tagvalue);
                 break;
             case ChooseTag:
                 if (tagvalue =="1")
                 {
                     Managers.Quest.UpdateQuest(currentQuestIndex);
                     Debug.Log("Update!"+Managers.Quest.GetQuestData(currentQuestIndex).questState);
                 }
                 break;
             case EndTag:
                 if(tagvalue =="1")
                 {
                     Managers.Quest.UpdateQuest(currentQuestIndex);
                     Debug.Log("Update!" + Managers.Quest.GetQuestData(currentQuestIndex).questState);
                 }
                 break;
             default:
                 Debug.LogWarning("Tag exists but not handled");
                 break;
         }

     }
 }

 

이렇게 해주고 대화를 하나 만들어주자.

Sori1.ink

이렇게 해주고 테스트해보자.

정상적으로 작동하는 것을 볼 수 있다.

+ Recent posts