본문 바로가기

포트폴리오/서버연동 온라인 arpg - Knight Online

[포트폴리오(Knight Online)] - 퀘스트 시스템 구현

 

 

 이번에는 포트폴리오에서 구현한 퀘스트 시스템에 대해 정리해보려고 한다.

 

 

 

 

 퀘스트 시스템의 경우 인터넷에 정보가 꽤나 있는 편이었지만, 내가 원하는 체계적이고 확장성이 있는 방식의 퀘스트 시스템은 없었다.(NPC에게 물건을 가져다 주거나 몬스터를 잡는 것 등 단편적인 정보밖에 없었다.) 그래서 내가 여태껏 봐왔던 게임들의 퀘스트 시스템을 참고하여 직접 구현하기로 결정하였다.

 

 

 

다양한 퀘스트

 

 

퀘스트의 종류?

 

 

 

 

 게임에서의 퀘스트는 매우 종류가 다양한데, 그에 따라 퀘스트의 클리어 조건도 매우 다양하다. 매우 일차원적인 사고방식으로 퀘스트를 구현한다면 구현하고 싶은 퀘스트를 한땀한땀 클라이언트에 클래스를 작성해가며 구현해야겠지만, 그런식으로 구현하는 것은 원치 않았다. 구현할 때야 편하겠지만, 그런식으로 퀘스트를 수십 수백개 구현한다고 치면 노가다도 그런 노가다가 없을 것이기 때문이다.

 

 

 

 

 

 사실 퀘스트를 잘 들여다보면 모든 퀘스트가 전부 달라보이지만, 퀘스트들의 클리어 조건은 어느정도 카테고리가 정해져있다. 해당 퀘스트의 이름이나 스크립트가 다르게 때문에 플레이하는 입장에서는 그 퀘스트들이 전부 다르다고 느낀다고 생각하였다.

 예를 들면 퀘스트를 클리어 조건 별로 나누자면, 특정 장비 장착 시 클리어 되는 퀘스트, 특정 스테이지를 클리어 시 클리어되는 퀘스트, 특정 몬스터를 몇마리 잡으면 클리어되는 퀘스트 등, 클리어 조건은 정해져 있지만 퀘스트의 스크립트를 달리함으로써 다른 퀘스트처럼 보이게끔 만들 수 있다고 생각한다. 이 부분에 주목하여 퀘스트 시스템을 구현하였다.

 

 

 

 

 

퀘스트 데이터

 

 퀘스트 시스템을 구현하기에 앞서 퀘스트와 관련된 모든 데이터들을 구글 스프레드 시스템을 이용하여 관리하였다. 게임에 퀘스트와 관련된 데이터를 넣지 않아도, 게임 접속 시 퀘스트에 필요한 데이터를 스프레드 시스템에 http get 메시지를 보내 데이터를 얻어오게끔 하였다.

 

 

 

 

 

 퀘스트 데이터를 보면 퀘스트를 구별하기 위한 ID와 클리어 조건을 체크하기 위한 Type이 명시되어 있다. 그 외에 퀘스트의 이름 및 보상관련 데이터도 추가하였다. 이는 다음에 구현할 보상 시스템에서 이용하기위해 추가하였다.

 

 

 

 

 

 

 

 

NPC Dialogue 데이터

 

 

 퀘스트 시스템을 구현하면서, 퀘스트를 NPC에게 받는 방식으로 구현하기 위해 NPC Dialogue 시스템도 동시에 구현하였다. NPC의 대화 스크립트또한 스프레드 시트와 연동하여 게임 접속 시 데이터를 얻어 오게끔 하였다.

 

 

 

 

 사실 이런 스크립트 데이터는 게임에 따라 클라이언트에 때려박는 경우도 있고, 정답이 없다고 생각한다. 다만 이 플젝에서 이런 스크립트 데이터를 전부 밖으로 빼서 관리하는 이유는 데이터 수정의 용이함에 있다. 만약 아이템의 수치나 퀘스트의 보상 등을 변경하고자 한다면 굳이 게임 내의 오브젝트를 건드릴 필요 없이 스프레드 시트의 데이터만 변경해주면 되기 때문이다.

 

 

 

 

 실제 업무를 한다고 생각하여도 아이템의 수치나 스크립트 오탈자 수정등은 굳이 프로그래머가 에디터를 켜서 할 필요가 없기에 이런 방식이 좀 더 효율적이지 않을까 하는 판단하에 모든 수치, 스크립트 관련 데이터는 스프레드 시트에서 받아와서 게임 내 객체로 만들어 사용하게 끔 만들었다.

 

 

 

 

 

NPC InterAction 시스템

 

 게임에 접속 시 퀘스트를 획득할 수 있는 NPC의 경우 "!" 퀘스트 마커를 머리위에 띄우게 하였다. 이 경우 말을 걸어 퀘스트를 획득 할 수 있다.

 

 

 

 

 

 

스크립트 출력

 

 F키를 눌러 말을 걸면 데이터 시트에 있던 스크립트가 정상적으로 파싱되어 UI에 출력되는 것을 확인 할 수 있다.

 

 

 

 

// NPC script 파싱
    void ParseScript(string data)
    {
        foreach(string scriptItem in data.Split("\t\tEOS"))
        {
            string[] script = scriptItem.Split("\t\t");
            int NPCID = int.Parse(script[0].Split("\t")[0]);
            int ScriptID = int.Parse(script[0].Split("\t")[1]);

            script[0] = script[0].Split("\t")[2];

            int QuestNum = 0; // 기본 값은 0 -> 퀘스트 없음
            if (script[script.Length - 1].Split("@").Length > 1)
            {
                string[] dialougeAndQuest = script[script.Length - 1].Split("@");
                script[script.Length - 1] = dialougeAndQuest[0];
                QuestNum = int.Parse(dialougeAndQuest[1]);
            }

            // 퀘스트 번호가 0일 때, 퀘스트가 없는 일반 스크립트
            // 0 이 아닐 때, 대화시 해당 퀘스트를 받는 대화
            NpcSriptDict.Add((NPCID, ScriptID), (script, QuestNum));
        }

        Managers.Dialouge.DialoueDict = NpcSriptDict;
    }

 

 

 

 스크립트 파싱의 경우 위와 같이 작성하였다. 구글 스프레드 시트에서 데이터를 tsv방식으로 보내도록 설정하였기 때문에 \t를 이용해서 데이터를 구분하였다.

 

 

 

 

파싱된 데이터는 게임내에서 사용하기 위해 클래스화 하여 초기화된다.

 

 

 

 

 

 

DB에 퀘스트 데이터 생성

 

 NPC와의 대화를 끝마치면 서버로 퀘스트 획득 패킷을 전송하고 DB에 해당 플레이어가 퀘스트를 진행중임을 나타내는 데이터를 insert한다. 퀘스트의 진행 상태에 따라 NPC의 대화 스크립트도 달라지게 설계 하였다. 이를 확인하기 위해 퀘스트 데이터의 IsCleared 값을 강제로 True로 바꿔보겠다.

 

 

 

 

 

 

퀘스트 클리어 시

 

 DB의 값을 강제로 바꾸고 게임을 종료 후 재접속 하였다. 퀘스트 보상 시스템이 아직 구현되지 않아 테스트를 위해서는 DB의 값을 강제로 바꿔줘야한다.

 

 

 

 

 

 게임에 접속 시 아까와 다르게 NPC위의 퀘스트 마커가 "?"로 바뀌어 있으며 퀘스트 UI위에 '보상 획득 가능' 이라는 UI가 활성화 되어 있다.

 

 

 

 

 

 

퀘스트 클리어 시 스크립트

 

NPC에게 말을 걸자 아까와는 다른 스크립트가 출력되는 것을 확인 할 수 있다.

 

 

 

 

 퀘스트 시스템의 경우 이런 식으로 구현을 하였다. 퀘스트가 NPC에게 말을 걸어 얻는 방식이 아니라 처음부터 주어져 있는 업적 방식의 퀘스트도 있으나 이것은 지금 까지 구현한 퀘스트를 조금 변형 시키면 구현할 수 있는 부분이라 생각하여 따로 구현을 하진 않을 것 같다.

 

 

 

 

 

 이번에 학기 중에 퀘스트 시스템 및 대화 시스템을 구현하였는데 정말 쉽지 않은 것 같다. 특히 게임 내에서 오브젝트가 로딩되는 타이밍과 온라인상에서 데이터를 얻는 타이밍을 내가 조절 할 수 있지 않다보니 비동기 처리에서 상당히 애를 먹었다. 최대한 Command pattern을 이용해서 비동기 문제를 없애도 버그가 발생할 때도 가끔 있고, 참 어이가 없는건 디버깅을 하면 버그가 절대로 일어나질 않는다.(빌드해서 실행해도 안일어 난다.) 오로지 유니티 에디터에서 실행만 시키면 가끔 비동기 이슈가 나는데 디버깅도 안되니 참 골치가 아프다.

 

 

https://teachingforme.tistory.com/34

 

[포트폴리오(Knight Online)] - 비동기 버그 관련 수정

지난번 퀘스트 시스템을 구현하면서 비동기 문제 때문에 참 골치가 아팠는데, 결국 원인을 찾긴 하였다. 디버깅을 해도 이게 발생을 할 때도 있는데, 안할 때가 많아서 원인을 찾기가 쉽지 않았

teachingforme.tistory.com

 

 

 

버그를 잡긴 잡았다. 역시 정답은 무한한 디버깅 뿐이다.

 

 

 

 

 

 그리고 현재 보상 시스템이 미구현이라 퀘스트 시스템이 완전히 완성되었다고 보긴 힘들다. 버그를 잡는 것 만큼이나 시스템을 설계하고 UI에 뿌리고 하는 작업도 만만치 않았다. 또한 퀘스트 정보를 전부 서버에서 저장해야 하므로 클라에서의 정보를 서버와 동기화 시켜야하니 신경 써줘야할 부분이 많았다.