03/18 본캠프 #58

guno park·2024년 3월 18일
0

본캠프

목록 보기
58/77
post-custom-banner

대화 기록 저장하기

중요도에 따라, 대화 타입에 따라 나의 선택지도 포함한 대화의 기록을 저장해보려고 한다.

저장하기 위해 사용되는 class는 3가지로,
단일 대화의 Name, Log를 저장하는 chatlogData

public class chatlogData //대화 하나 저장
    {
        public string Name;
        public string Log;
    }

한 Quest의 전체 대화를 저장하는 chatlogdic

 public class chatlogdic //한 대화의 전부
    {
        public Dictionary<int,List<chatlogData>> saveOneLog = new Dictionary<int, List<chatlogData>>();
    }

그리고 모든 대화를 저장하는 AllChatLog

 public class AllChatLog //전체 대화 로그
    { 
        //Dictionary<int, chatlogData> => int = Quest 순서, ChatlogData = 퀘스트 안의 대화 내역
        public Dictionary<string,chatlogdic> allChatlog = new Dictionary<string, chatlogdic>();
    }

이렇게 데이저 저장을 위한 Class를 구성해주었다.

구성한 class 활용하기

chatlog라는 기능을 활용하기 위해 ChatLogManager라는 클래스를 추가로 구성한다.

DialogueManager에서 현재까지 진행된 대화를 저장하는 방식으로 구성하기 위해 간단하게 싱글턴화하고 앞서 만든 AllChatLog 클래스를 새로 선언해준다.

[HideInInspector] public AllChatLog allChatLog = new AllChatLog();
    private List<GameObject> _PrefabList = new List<GameObject>();

    public static ChatLogManager instance; 
    private void Awake()
    {
        if (instance == null)
            instance = this;
        else
            Destroy(gameObject);
    }

Log 저장하기

일반대화

void Savelog()
    {
        if (_questdic[Targetname][questcount - 1].QuestType == QuestType.Normal)
        {
            string name = _dialogdic[contextcount].Name;
            string log = _dialogdic[contextcount].Log;
            chatlogData saveSingleLog = new chatlogData();
            saveSingleLog.Name = name;
            saveSingleLog.Log = log;
        
            if (!allchatlog[Targetname].saveOneLog.ContainsKey(questcount))
                allchatlog[Targetname].saveOneLog.Add(questcount,new List<chatlogData>());
            allchatlog[Targetname].saveOneLog[questcount].Add(saveSingleLog);    
        }
    }

저장하는 방법으로
1. 현재 진행되는 Quest의 타입이 저장이 필요한 타입인지 검사한다.
2. 저장하기로 결정됬다면 현재 dialogue에서 Name과 Log를 각각 새로운 chatlogData에 저장한다.
3. allchatlog에 TargetName으로 만들어진 Key가 없다면 새로 추가하여 저장하고, 있다면 Add하여 List에 추가해준다.

선택지

선택지의 경우 조금 다르다.
기능과 메서드의 내용이 거의 동일하나, Log가 아닌 Event_Log를 저장해야한다.

 void savelog(int index)
    {
        if (_questdic[Targetname][questcount - 1].QuestType == QuestType.Normal)
        {
            string name = "Player"; //형사 이름으로 변경
            string log = _dialogdic[contextcount].Event_Log[index];
            chatlogData saveSingleLog = new chatlogData();
            saveSingleLog.Name = name;
            saveSingleLog.Log = log;

            if (!allchatlog[Targetname].saveOneLog.ContainsKey(questcount))
                allchatlog[Targetname].saveOneLog.Add(questcount, new List<chatlogData>());
            allchatlog[Targetname].saveOneLog[questcount].Add(saveSingleLog);
        }
    }

매개변수로 int를 추가해 내가 몇번째 선택지를 골랐는지, 그 선택지의 내용이 무엇인지를 저장한다.

Log 출력하기

전체 대화의 기록을 확인하는 부분은 아직 UI가 없어 만들지 않았고, 현재 대화의 이전 기록을 확인하는 부분만 있다.

foreach (chatlogData chat in allChatLog.allChatlog[DialogueManager.Targetname].saveOneLog[DialogueManager.questcount])
        {
            var obj = Instantiate(_chatLogPrefab, _chatLogPosition.transform);
            if (obj.TryGetComponent(out ChatLogSet chatLogSet))
            {
                chatLogSet.LogSetting(chat);
                _PrefabList.Add(obj);
            }
        }

allchatlog에 저장되는 Dic의 형태가 string(TargetName), int(questcount)형태로 저장된다.

DialogueManager에서는 현재 진행되고 있는 대화가 다 종료되기 전까지 타겟의 이름과 퀘스트의 idx를 기억하고 있기때문에 현재 진행되고 있는 대화의 Log를 확인할 수 있다.

선택지 제거하기

한 번 열람한 선택지의 경우, 다시 보여줄 이유가 없기도 하고, 데이터를 구성하는데 방해요소였기에 제거하기로 하였다.

먼저 json에서 선택지를 반복하는 경우 dialogueType을 Loop로 변경했다.
그리고 Event_Log_State 항목을 bool[]로 추가해서 해당하는 만큼 False로 둔다.

//선택지 출력 시
for (int i = 0; i < data.Event_Log.Length; i++)
        {
        	//일반 선택지면 바로 출력, 아니라면 Event_Log_State 확인.
            if (data.Log_Type == Log_Type.choose||!data.Event_Log_State[i])
            {
                choice_btn[i].gameObject.SetActive(true);
                choice_btn[i].GetComponentInChildren<TextMeshProUGUI>().text = data.Event_Log[i];    
            }
        }

//선택지를 골랐을 때 반복하는 타입이면 true로 바꿔 다음부터 안나오게 하기.
if(_dialogdic[contextcount].Log_Type==Log_Type.Loop)
            _dialogdic[contextcount].Event_Log_State[index] = true;

트러블슈팅

클로저 문제(?)

문제현상 : 대화를 저장할 때, ChatLogManager에 3가지 타입에 대해 모두 선언하고 활용하다보니
값이 변경되면 이전에 저장된 값들도 모두 변경되는 일이 발생

ChatLogManager.instance.chatlogData.Name = _dialogdic[contextcount].Name;

문제원인 : 위와 같이 작성하여 _dialogdic[contextcount].Name을 참조하는 형태로 저장되기 때문에, 그 값이 바뀔때마다 모든 내용이 변경되는 것이 당연하다. 사실상 같은 내용을 작성하고 있기 때문에

문제 해결 : chatlogData saveSingleLog = new chatlogData(); 라는 형태로 새로운 스코프 내에서 활용될 수 있도록 새로운 class를 만들어 저장해주면 된다.

캐싱 문제

문제 현상 : 데이터를 사용하기 위해 여러 클래스를 만들어 저장하다보니, 호출할 때 길이가 길어짐. 근데 메서드마다 따로 캐싱하기에 놓치는 것도 많고 복잡함.

문제 해결 : 제일 많이 공통되는 부분만 데이터세팅이 끝날 때 캐싱해주거나, 아예 시작부터 캐싱한 값을 따로 만들어주었다.

 void SetDatas()
    {        
        DialogueManager.instance._questdic = _questDic.DialogueQuestDic;
        DialogueManager.instance. _dialogdic = dic.DialogueDic;
    }
post-custom-banner

0개의 댓글