내일배움캠프 TIL

내일배움캠프 83일차 TIL "CSV형태의 대사 변환"

Jooglorystar 2025. 1. 15. 20:55

 

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

 

 

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

 

TextAsset으로서 참조된 대화 파일

 

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 외부에서 데이터를 쉽게 작업할 수 있는 환경을 제공한다. 이를 통해 대화 스크립트를 작성하는 시나리오 라이터나 기획자와의 협업이 용이해지며, 개발자뿐 아니라 다양한 팀원들이 효율적으로 참여할 수 있는 구조를 마련할 수 있을 것이다.