게임에서 퀘스트는 방향성을 제공해 주고 게임의 목적성과 재미를 높여주며, 진행 상황을 추적하고 보상을 제공하여 게임을 보다 흥미롭게 만들어줍니다. 퀘스트 시스템을 구현하고 정리하였습니다.
💬 서론
- 본 글은 게임을 모두 만든 후에 작성한 글로 핵심 주제 외 클래스 및 다른 기능에 대한 함수가 포함될 수 있습니다.
📖 구현 내용
- 적 처치, 아이템 습득에 대한 퀘스트를 구현합니다.
- 플레이어는 퀘스트를 받고 퀘스트를 완료할 수 있습니다.
- 퀘스트 상태를 확인하여 상태별로 이벤트를 처리할 수 있습니다.
- 스크립터블 오브젝트로 퀘스트의 데이터를 관리합니다.
- 스크립터블 오브젝트를 프로젝트 폴더 내에서 관리하고, 이 데이터를 자동으로 불러옵니다.
- ID를 이용하여 고유한 퀘스트의 중복 여부를 검사할 수 있습니다.
- 하나의 퀘스트에서 여러 개의 목표 중 하나만 수행해도 퀘스트를 완료하는지에 대한 여부를 설정할 수 있습니다.
- 퀘스트 콘텐츠를 보여주고 현재 진행 시점, 완료한 퀘스트들의 정보를 볼 수 있습니다.
⚒️ 구현
- 이번 글에서는 퀘스트 콘텐츠 매니저를 사용할 때 풀 사이즈 UI창을 구현하고 구성요소 중 하나인 QuestFullContent 프리팹에대해 다루겠습니다.
· CompactContent
더보기
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using System.Text;
namespace Quest
{
public class QuestCompactContent : MonoBehaviour
{
protected QuestData mQuestData;
[Header("타이틀 텍스트 라벨")]
[SerializeField] public TextMeshProUGUI TitleTextLabel;
[Header("콘텐츠 텍스트 라벨")]
[SerializeField] public TextMeshProUGUI ContentTextLabel;
public void Init(QuestData questData)
{
this.mQuestData = questData;
}
public virtual void UpdateCompactQuestContents(QuestContentData contentData)
{
//타이틀 제목 변경
{
string compactTitleText = ((QuestManager.Instance.CheckQuestState(mQuestData.questId) == QuestState.CLEAR || QuestManager.Instance.CheckQuestState(mQuestData.questId) == QuestState.CLEARED_PAST) ? "<color=green>(완료)</color>" : null) + contentData.title;
TitleTextLabel.text = compactTitleText;
}
//콘텐츠 내용 변경을 위한 스트링빌더
StringBuilder contentBuilder = new StringBuilder();
for (int i = 0; i < contentData.compactContent.Length; ++i)
{
if (contentData.compactContent[i] == '{') // String Format 시작점을 찾음
{
int formatFrom = i;
for (; i < contentData.compactContent.Length; ++i) // String Format 시작점부터 '}'을 찾음
{
if (contentData.compactContent[i] == '}')
{
//포맷 인덱스 획득
int formatIndex = int.Parse(contentData.compactContent.Substring(formatFrom + 1, i - formatFrom - 1));
//포맷 인덱스에 맞는 문자열 가져오기
contentBuilder.Append(GetFormatIndex(mQuestData, formatIndex));
break;
}
}
}
else
{
contentBuilder.Append(contentData.compactContent[i]);
}
}
ContentTextLabel.text = contentBuilder.ToString();
}
private string GetFormatIndex(QuestData questData, int formatId)
{
for(int i = 0; i < questData.allQuests.Length; ++i)
{
if(questData.allQuests[i].formatId == formatId)
return questData.allQuests[i].GetFormatText();
}
Debug.LogErrorFormat("{0}에서 {1}번의 퀘스트 포맷 인덱스가 없음!", questData.name, formatId);
return null;
}
}
}
protected QuestData mQuestData;
- 현재 이 클래스가 담당하는 퀘스트 데이터입니다.
- 퀘스트 데이터 내부의 변수를 읽어 적절하게 텍스트 콘텐츠를 표시합니다.
[Header("타이틀 텍스트 라벨")]
[SerializeField] public TextMeshProUGUI TitleTextLabel;
- 타이틀 텍스트 라벨입니다.
- 퀘스트의 이름을 표시합니다.
[Header("콘텐츠 텍스트 라벨")]
[SerializeField] public TextMeshProUGUI ContentTextLabel;
- 콘텐츠 텍스트 라벨입니다.
- 현재 퀘스트의 진행 상태를 요약하여 보여줍니다.
public void Init(QuestData questData)
{
this.mQuestData = questData;
}
- 이 클래스가 생성될때 호출되며 퀘스트 데이터를 이 클래스에 레퍼런스해줍니다.
public virtual void UpdateCompactQuestContents(QuestContentData contentData)
{
//타이틀 제목 변경
{
string compactTitleText = ((QuestManager.Instance.CheckQuestState(mQuestData.questId) == QuestState.CLEAR || QuestManager.Instance.CheckQuestState(mQuestData.questId) == QuestState.CLEARED_PAST) ? "<color=green>(완료)</color>" : null) + contentData.title;
TitleTextLabel.text = compactTitleText;
}
//콘텐츠 내용 변경을 위한 스트링빌더
StringBuilder contentBuilder = new StringBuilder();
for (int i = 0; i < contentData.compactContent.Length; ++i)
{
if (contentData.compactContent[i] == '{') // String Format 시작점을 찾음
{
int formatFrom = i;
for (; i < contentData.compactContent.Length; ++i) // String Format 시작점부터 '}'을 찾음
{
if (contentData.compactContent[i] == '}')
{
//포맷 인덱스 획득
int formatIndex = int.Parse(contentData.compactContent.Substring(formatFrom + 1, i - formatFrom - 1));
//포맷 인덱스에 맞는 문자열 가져오기
contentBuilder.Append(GetFormatIndex(mQuestData, formatIndex));
break;
}
}
}
else
{
contentBuilder.Append(contentData.compactContent[i]);
}
}
ContentTextLabel.text = contentBuilder.ToString();
}
- 현재 퀘스트 상태를 고려하여 적절하게 텍스트를 설정합니다.
- GetFormatIndex 함수를 호출하여 현재 퀘스트 데이터의 포맷 아이디에 맞는 적절한 텍스트를 가져옵니다.
- String.Format에 영감을 받아 디자인하였습니다.
- 이 함수를 이용하여 현재 진행 값을 보여줄 수 있습니다.
- 예시로 아이템이 3개가 남았다면, "[1/4]개 획득하기"처럼 보여지게 할 수 있습니다.
private string GetFormatIndex(QuestData questData, int formatId)
{
for(int i = 0; i < questData.allQuests.Length; ++i)
{
if(questData.allQuests[i].formatId == formatId)
return questData.allQuests[i].GetFormatText();
}
Debug.LogErrorFormat("{0}에서 {1}번의 퀘스트 포맷 인덱스가 없음!", questData.name, formatId);
return null;
}
- formatId에 맞는 적절한 텍스트를 가져오고 리턴해줍니다.
· UI 설정
- 전체 구성은 다음과 같습니다.
✅ 사용
- "[유니티] 퀘스트 시스템(3) - 콘텐츠 매니저"에서 사용되는 이 프리팹은 콘텐츠 매니저의 mQuestCompactPrefab에 할당해야합니다.
'unity game modules' 카테고리의 다른 글
[유니티] 피해 효과 (Damage effect overlay) (0) | 2023.08.28 |
---|---|
[유니티] 퀘스트 시스템(5) - 풀사이즈 UI (0) | 2023.04.11 |
[유니티] 퀘스트 시스템(3) - 콘텐츠 매니저 (0) | 2023.04.11 |
[유니티] 퀘스트 시스템(2) - 퀘스트 매니저 (0) | 2023.04.11 |
[유니티] 퀘스트 시스템(1) - 퀘스트 데이터 (0) | 2023.04.11 |