
현재 진행중인 게임에서는 NPC와 상호작용시, 대화 스크립트에 적혀있는 텍스트를 출력하는 기능이 존재한다.

이러한 식으로 작성된 csv 파일을 각 NPC마다 참조하고, 상황에 맞게 대사를 사용하게 할 수 있게 했다.

public class NPCDialogueData : MonoBehaviour
{
private DialogueParser _parser;
[SerializeField] private TextAsset _textAsset;
[SerializeField] private NpcDataSO _npcDataSo;
private Dictionary<int, Dialogue> _dialogueDictionary = new Dictionary<int, Dialogue>();
private void Awake()
{
_parser = GetComponentInParent<DialogueParser>();
Dialogue[] dialogues = _parser.Parse(_textAsset);
for (int i = 0; i < dialogues.Length; i++)
{
_dialogueDictionary.Add(i + 1, dialogues[i]);
}
}
}
참조받은 대화 스크립트를 Parser를 통해 게임에서 정리할 수 있도록 만들었다.
public class DialogueParser : MonoBehaviour
{
public Dialogue[] Parse(TextAsset p_csvData)
{
List<Dialogue> dialoguesList = new List<Dialogue>();
string[] data = p_csvData.text.Split(new char[]{'\n'});
for (int i = 1; i < data.Length;)
{
string[] row = data[i].Split(new char[] { ',' });
Dialogue dialogue = new Dialogue();
dialogue.characterName = row[1];
List<string> contextList = new List<string>();
List<FaceType> faceTypeList = new List<FaceType>();
do
{
contextList.Add(row[2]);
if (Enum.TryParse(row[3], true, out FaceType faceType))
{
faceTypeList.Add(faceType);
}
if (++i < data.Length)
{
row = data[i].Split(new char[]{','});
}
else
{
break;
}
} while (row[0] == string.Empty);
dialogue.contexts = contextList.ToArray();
dialogue.faceType = faceTypeList.ToArray();
dialoguesList.Add(dialogue);
}
return dialoguesList.ToArray();
}
}
string[] data = p_csvData.text.Split(new char[]{'\n'});
처음에는 각 CSV 데이터를 줄 바꿈을 기준으로 각 줄을 문자열의 배열로 저장한다.
반복문으로 data를 순회한다. 첫 번째 줄은 ID나 CharacterName과 같이 게임에 사용되지 않는 데이터이므로, data[1]부터 시작한다.
string[] row = data[i].Split(new char[] { ',' });
data[i]를 쉼표로 나누어 배열로 변환하며, 각 요소는 ID, 캐릭터 이름, 대화 본문, 그리고 얼굴 표정을 나타낸다.
1,하비,안녕? 난 농사하는 방법을 알려줄 하비야,Normal
,,우선 농사를 위해서는 마을의 상점에서 살 수 있는 괭이` 물뿌리개` 씨앗이 필요해.,Talk
,,아이템을 다 구했으면 내 옆의 넓은 밝은 색의 공터에서 괭이를 사용해 땅을 경작할 수 있어.,Happy
,,경작할 수 있는 곳은 이 옆 공터 뿐이야.,Talk
즉 위 row에는 각각 '1', '하비', '안녕? (후략)', 'Normal' 을 가지고 있는 배열이 된다.
public class Dialogue
{
public string characterName;
public string[] contexts;
public FaceType[] faceType;
}
그 다음은 Row를 해당 정보를 Dialogue 형태로 변환하는 부분이다. row[1] 이 캐릭터의 이름이 된다.
do
{
contextList.Add(row[2]);
if (Enum.TryParse(row[3], true, out FaceType faceType))
{
faceTypeList.Add(faceType);
}
if (++i < data.Length)
{
row = data[i].Split(new char[]{','});
}
else
{
break;
}
} while (row[0] == string.Empty);
그리고 row[2]를 대화문 본문에, row[3]을 faceType으로 지정한다.
그리고 이를 data의 다음 줄에도 계속 하는데, row[0]가 비어 있는 동안에는 같은 대사로 간주하고 계속해서 context와 faceTypeList에 추가한다.
그리고 해당 리스트를 배열로 변환하고 Dialogue를 반환한다.
public class NPCDialogueData : MonoBehaviour
{
private DialogueParser _parser;
[SerializeField] private TextAsset _textAsset;
[SerializeField] private NpcDataSO _npcDataSo;
private Dictionary<int, Dialogue> _dialogueDictionary = new Dictionary<int, Dialogue>();
private void Awake()
{
_parser = GetComponentInParent<DialogueParser>();
Dialogue[] dialogues = _parser.Parse(_textAsset);
for (int i = 0; i < dialogues.Length; i++)
{
_dialogueDictionary.Add(i + 1, dialogues[i]);
}
}
}
위 Paser에서 작업이 끝나면 각 NPC는 자신의 대사를 딕셔너리에 가지게 된다.
이러한 CSV 기반의 대화 데이터 관리 방식은 Unity 외부에서 데이터를 쉽게 작업할 수 있는 환경을 제공한다. 이를 통해 대화 스크립트를 작성하는 시나리오 라이터나 기획자와의 협업이 용이해지며, 개발자뿐 아니라 다양한 팀원들이 효율적으로 참여할 수 있는 구조를 마련할 수 있을 것이다.
'내일배움캠프 TIL' 카테고리의 다른 글
| 내일배움캠프 85일차 TIL "가비지 컬렉터" (0) | 2025.01.17 |
|---|---|
| 내일배움캠프 84일차 TIL "클래스와 구조체의 차이" (0) | 2025.01.16 |
| 내일배움캠프 82일차 TIL "퀘스트 완료 처리" (0) | 2025.01.14 |
| 내일배움캠프 81일차 TIL "퀘스트 감지 처리" (0) | 2025.01.13 |
| 내일배움캠프 80일차 TIL "NPC 위치에 따른 표시" (0) | 2025.01.10 |