rejin 아바타

서브컬처 게이머

세상의 모든 아름다운 것들을 위하여

다이얼로그 테이블 설계 대표 이미지

‘다이얼로그 테이블 설계’ – #2. 다이얼로그 시스템 구현하기

들어가는 글

image 3 1
순수 비주얼 노벨이 설 자리는 점점 좁아지고 있지만, 그 찬란한 유산들은 다양한 형태로 변주하며 플레이어에게 새로운 경험을 전달하고 있다.
ⓒ헤븐 번즈 레드

필자는 저번에 ‘비주얼 노벨 기반 시스템’이라는 주제로 글을 작성했다.

(링크)

위 글에서 정리한 비주얼 노벨(정확히는 다이얼로그 시스템)을 만들기 위해서 필요한 코어 스펙은 아래와 같다.

  • 다이얼로그 시스템 기획 – 캐릭터 등장/퇴장, 캐릭터 이동, 캐릭터 포즈 변화, 캐릭터 복수 등장
  • 다이얼로그 해상도 대응 기획 – 16:9, 4:3 등
  • 다이얼로그 UI 기획 – 대사창, 스킵 버튼, 스킵 다이제스트, 확인/취소 버튼, UI 사운드 볼륨 바 등
  • 다이얼로그 BGM, SFX, VOC 리소스 연결 기획 등
  • 선택지 기획 – 분기 기능, 버튼 UI 등
  • 스토리 점프 기능 등

위 기능들은 대부분의 비주얼 노벨들이 갖추고 있거나 갖춰야 할 기본중의 기본 기능들이다.

사실, 비주얼 노벨을 만들기 위해서 특화된 다양한 엔진들이 존재한다. (렌파이, 네코노벨 등)

비주얼 노벨을 만들기에는 위 엔진으로도 충분하지만, 최근 서브컬처 게임의 추세는 비주얼 노벨 시스템 + ‘알파’를 추가하는 경우가 많다.

실무에서는 유니티나 언리얼 엔진을 사용하는 경우가 대다수이며, 작업환경에 따라 비주얼 노벨 시스템을 새로 만들어야하는 경우도 있다.

그래서 저번 글에 이어서 ‘비주얼 노벨 기반 시스템’을 갖추기 위해 비주얼 노벨 시스템을 완전히 새로 만든다고 가정하고, 어떤 부분들에 대해 고민하면 좋을지에 대해 다뤄보도록 하겠다.

이번 글의 주제는 바로 시나리오 기획자가 스크립트를 작성할 수 있는 구조, 즉 ‘다이얼로그 테이블 설계’에 대해 다뤄보도록 하겠다.

현 상황 파악하기

다이얼로그 테이블 설계 대표 이미지
유니티 엔진의 대표적인 개발자 친화적 에셋 ‘나니노벨’
5b3f739b a540 4aaf 89ca 4960696ab9f7
Excel이나 CSV 구조로 스크립팅이 가능한 유니티 엔진의 대표 에셋인 ‘우타게’

나는 당신이 어떤 프로젝트에 합류할지, 또는 합류한 상태일지 모르겠지만, 아마 당신의 프로젝트는 높은 확률로 ‘유니티’나 ‘언리얼’ 엔진을 사용할 것이다.

우리나라 게임 회사 대부분은 위 두 가지 엔진을 이용해 게임을 개발한다. 간혹 자체엔진을 쓰거나 cocos2d, Godot 엔진 등을 활용하기도 하지만 거의 드물다.

필자는 먼저 결론부터 이야기하겠다.

매니저를 설득할 수 있다면 다이얼로그 시스템은 에셋 스토어에서 구입하라.

에셋 스토어에는 저렴한 가격에 다이얼로그 시스템 구축을 위한 좋은 에셋들이 몇 가지 있다.

굳이 다이얼로그 시스템을 구현하기 위해 에셋을 구입하지 않고 인력과 시간을 사용하는 건 굉장히 가성비가 나쁘다.

비싸봐야 몇십~몇백 달러면 적어도 며칠에서 몇 주가 걸리는 프로그래머의 귀중한 맨파워를 절약할 수 있다.

아래는 비주얼 노벨 시스템을 갖추기 위한 유니티 엔진과 언리얼 엔진의 대표적인 에셋들이다.

유니티 엔진

언리얼 엔진

다시 한번 강조하지만 다이얼로그 시스템은 에셋 스토어에서 구입하는 게 훨씬 가성비가 좋다.

그런데 에셋이 만병통치약처럼 모든 경우에 유효한 선택지인 것은 아니다.

만약 개발하고자 하는 우리 게임의 비전이 우리 게임의 플레이어로 하여금 완전히 색다른 ‘경험’을 주고자 한다면 에셋으로는 한계가 있다.

스크립팅을 진행하는 시나리오 기획자의 스타일도 중요하다. 만약 엔진을 통해 실시간으로 다이얼로그 각 요소를 컨트롤하는 걸 원하는 기획자라면, 추가 구현은 불가피하다.

우리 프로젝트에 실력있는 아웃게임 전담 프로그래머가 있다면 다이얼로그 시스템을 구현하는 것도 장기적인 개발 측면에서 좋은 선택이 될 수 있다.

이제부터 본론이다. 다이얼로그 시스템을 한번 만들어보도록 하자.

다이얼로그 시스템 기획서 쓰기


다이얼로그 시스템은 겉보기에는 간단해보이지만 기획서 한 장으로는 필요한 내용을 다 적을 수 없을 정도로 고려해야할 게 많다.

특히 ‘화면 연출’을 풍성하게 하기 위해서는 연출 레퍼런스 조사와 개발 방향성 정립에만도 많은 시간을 필요로 한다.

실무에서는 ‘기획’과 ‘구현’이 병행될 때가 많아 기획서가 빨리 나와야하는 경우(예를 들어 오늘 퇴근 전까지)가 자주 발생한다.

이런 경우에 퇴근 전까지 밤을 새우면서 기획서를 쓸 수도 있겠지만, 필자가 제안하는 방법은 바로 ‘동심원 개발 방법론’에 입각한 ‘조각(버티컬 슬라이스) 기획’이다.

일단 큰 그림을 그려보자. 그리고 나(기획자)의 구현 결과물이 최종적으로 어떤 형태로 완성될지 상상해보자.

레퍼런스가 있으면 더 좋다. 필자의 경우, 기획서를 협업 부서에 전달할 때 어느 정도 유사도가 있는 게임의 레퍼런스는 꼭 첨부하는 편이다.

방향성만 올바르게 잡아도, 개발하면서 쓸데없이 일정을 낭비할 리스크를 최소화할 수 있다.

그렇다면 일단 대전제부터 잡아보자.

기획의 대전제

3D 비주얼 노벨 게임을 만들기 위한 다이얼로그 시스템을 기획한다.

최종사용자(플레이어)는 다이얼로그 시스템에서 아래의 게임과 유사한 룩앤필을 경험한다.

K 20240312 224115583 edited scaled
붕괴 3rd
image 19 edited
우마무스메
  • 게임화면은 크게 ‘대사창’, ‘3D 캐릭터’, ‘2D 배경’ 및 ‘편의성 버튼’으로 구성된다.
  • BGM이 재생되는 동안 Sound FX(효과음), Ambient Sound(AMB; 환경음), VOC(Voice; 캐릭터 보이스)를 출력할 수 있다.
  • 플레이어는 화면을 ‘터치’하여 스토리를 감상할 수 있다.

위처럼 ‘기획 목표’, ‘룩앤필’, 그리고 ‘대표 경험요소’만 정리해둬도 기획서를 작성하면서 길을 잃을 위험을 많이 줄일 수 있다.

기획은 어렵다. ‘중요하지 않은 부분에 너무 깊게 기획하는 나머지’ 중요한 기획이 후순위로 설계되거나 선행 디테일 요소와 서로 모순되기도 한다.

그래서 필자는 가장 중요한 것(코어)부터 탄탄하게 설계하면서, 그 위에 디테일을 쌓아올리는 것을 좋아한다.

우리 게임의 목표가 ‘멋진 캐릭터 연출’이라면, 그 목표를 이루기 위해서는 ‘캐릭터가 등장하는 방법’부터 탄탄하게 설정해야 한다.

image 2
다이얼로그 시스템 에셋 ‘우타게’의 대표 화면.
스프레드시트같은 구조의 테이블상에서 Command와 Arg 등의 열에 값을 입력해 비주얼 노벨 화면 연출을 컨트롤할 수 있다.

좀 더 나아가자면, 시나리오 기획자(시나리오 연출 제작 담당자)가 어떻게 테이블을 다루게 될 것이며, 장기적인 업데이트 플랜에 부합할 지도 함께 고민하면 금상첨화다.

그런 의미에서 코어 기획 단계에서 ‘테이블 구조’를 설계하는 일은 전체적인 다이얼로그 시스템 구조를 짜는 과정에서 가장 중요하다고 해도 과언이 아니다.

잘 설계한 테이블 구조는 개발자가 유지보수를 위한 공수를 들이지 않으면서도, 기획자가 원하는 자유도와 편의성을 제공한다.

글로벌 권역에 서비스하기 위해서 로컬라이즈 테이블 필요한 경우도 있다.

초기 단계에서부터 로컬라이즈 서비스를 고려해서 테이블을 설계한다면 추후 테이블이 불필요하게 늘어나거나 복잡해지는 것을 방지할 수 있다.

필자는 개인적으로 27인치 모니터 기준 한 화면 안에 다이얼로그 테이블의 모든 열(Attribute)이 들어오면 훌륭한 다이얼로그 테이블 구조라고 생각한다.

다이얼로그 테이블 설계하기

다이얼로그 테이블 설계를 위해, 이번 기획서의 구현 목표를 먼저 정하도록 하자.

필자는 아래의 4가지 목표는 초기 기획 단계부터 구현이 필요하다고 보았다.

  • 3D 캐릭터를 등장/퇴장시킬 수 있다.
  • 캐릭터가 특정 위치에서 등장하거나, 특정 좌표 사이를 이동할 수 있다.
  • 캐릭터의 모션과 표정이 변화할 수 있다.
  • 화면에 캐릭터가 2명 이상 등장할 수 있다.
02 Data Normalization Different Types Of Data Normalization In Databases 91f8d7a36b

다이얼로그 테이블은 기획자가 시나리오를 작성하거나, 화면 연출을 집어넣거나, 캐릭터 모션이나 표정 등을 컨트롤하는 등 전반적인 시나리오 디자인에 활용한다.

그 과정에서 필요한 ‘화면 연출’, ‘캐릭터 모션’, ‘캐릭터 표정’에 관한 데이터를 불러오는 것도 Dialog 테이블에서 함께 관리한다면 열이 굉장히 많이 늘어나 비효율적인 구조가 된다.

중복값이 생긴다든지, 하나의 레코드(행)을 작성하는데 불필요하게 많은 작성 시간이 소요되기도 한다.

이 경우 장기적인 유지보수가 곤란해지기 마련이다.

그래서 데이터 설계 초반 단계부터 각 목적에 따라 ‘데이터 구조화’를 진행하는 게 좋다.

가령, ‘카메라’와 관련된 것은 모두 ‘카메라’ 테이블에 몰아넣고, ‘캐릭터 위치’에 관한 모든 것은 모두 ‘캐릭터 위치’ 테이블에 몰아넣는 식이다.

모든 열을 이렇게 나누는 것은 오히려 비효율적이다. 데이터베이스 설계 단계에서부터 어떻게 하면 가장 효율적인 구조가 될 지 데이터 참조 관계를 적절히 설정하는 것이 좋다.

필자의 경우, Dialog 테이블은 순수히 ‘시나리오 대사 작성’과 ‘시나리오 연출 조립’을 위해 쓰이는 것을 선호한다.

이 구조에서는 시나리오 연출 조립을 위해 필요한 요소들(카메라 앵글, FOV, 화면 전환, 전환 시간, 캐릭터 등장 연출 등)은 다른 테이블의 ID(외래키)를 참조해야 한다.

이 구조가 100% 편리하다고 장담할 수는 없다. 그러나 필자는 현업에서 그러한 구조로 되어있는 테이블이 유지관리가 편리했다.

특히 ‘자주 손댈 필요 없는 데이터’들은 다른 테이블에 분리되어있는 게 좋다고 생각한다. 그래야 데이터 무결성의 이슈에서 조금이라도 더 빨리 자유로워지기 때문이다.

데이터 정규화에 대해서는 이 글에서는 다루지 않는다. 이 글의 주제가 ‘데이터베이스’가 아니기 때문이다.

만약 데이터 정규화에 관심이 있는 분이 계시다면 한번 찾아보시는 것을 권장한다.

필자는 기획자가 주로 다이얼로그(Dialog) 테이블을 핸들링하는 것으로 테이블 구조를 설계했다.

이 Dialog 테이블은 CameraView, CharPrefab, CharTransition, Char 등 목적에 따라 구분되는 4개의 테이블과 연결된다.

이 테이블들은 Dialog 테이블을 동작시키기 위한 종속적 관계에 놓인 테이블에 해당한다.

각 테이블의 모든 ID는 해당 테이블의 기본키(Primary Key)이다.

각 테이블의 관계는 아래와 같으며, Dialog 테이블의 각 열(Column)에서는 하위 테이블의 ID를 외래키(Foreign Key)로 참조한다.

도식화를 하자면 아래와 같다.

image 1
1차 다이얼로그 테이블 설계 단계에서 도식화한 구조.
각 테이블은 각각을 상징하는 색깔로 구분되며, Dialog 테이블에서 모두 만난다.

다이얼로그 테이블에서 각 열은 아래와 같은 목적을 위해 존재한다. 그리고 프로그래머에게 필요한 ‘예외처리’에 대한 부분도 간단히 명시했다.

  • ID: 해당 레코드의 고유 아이디에 해당한다.
    • Primary Key이므로 Null과 중복값을 허용하지 않는다.
  • CameraType: 화면을 비추는 카메라의 위치를 결정한다.
    • FOV와 미리 지정된 카메라 앵글에 따라 다이얼로그 화면 구도를 다르게 세팅할 수 있다.
    • 0 또는 Null 시 1(기본값)과 동일하게 동작한다.
    • CameraType 열의 ID에 없는 값을 입력했을 때 오류코드 2를 발생시킨다. (ErrMsg: ‘{TableName}에 해당하는 값이 없습니다.’)
  • CharPrefab: 해당 레코드에서 불러올 캐릭터와 애니메이션을 결정한다. (캐릭터의 ID와 연결된 Prefab의 모션을 호출한다.)
    • CharPrefab 테이블의 PrefabType에서 Body로 지정된 프리팹만 호출할 수 있다.
    • 키 입력 시 다음 레코드 값이 동일하면 현재의 애니메이션을 유지한다.
    • 키 입력 시 다음 레코드 값이 동일하지 않으면 다음 레코드의 번호에 지정된 애니메이션을 출력시킨다.
    • Null값을 허용한다.
      • 결과: 아무것도 불러오지 않는다.
      • 단, 경고코드 1을 발생시킨다. (Msg: {RecordNumber} 행의 CharPrefab 값이 공란입니다. 초기값으로 0을 입력하는 것을 권장합니다.)
    • CharPrefab 열의 ID에 없는 값을 입력했을 때 오류코드 2를 발생시킨다. (ErrMsg: ‘{TableName}에 해당하는 값이 없습니다.’)
  • CharPrefabAddon: 해당 레코드에서 불러올 캐릭터의 애드온 애니메이션을 결정한다. (캐릭터의 ID와 연결된 Prefab의 애드온 모션을 호출한다.)
    • CharPrefab 테이블의 PrefabType에서 Addon으로 지정된 프리팹만 호출할 수 있다.
    • 키 입력 시 다음 레코드 값이 동일하면 현재의 애니메이션을 유지한다.
    • 키 입력 시 다음 레코드 값이 동일하지 않으면 다음 레코드의 번호에 지정된 애니메이션을 출력시킨다.
    • Null값을 허용한다.
      • 단, CharPrefab 열이 공란일 때 해당 열의 값이 Null 또는 0이 아니면 오류코드 1을 발생시킨다. (ErrMsg: {RecordNumber} 행의 ‘CharPrefab이 비어있습니다.’)
    • CharPrefab 열의 ID에 없는 값을 입력했을 때 오류코드 2를 발생시킨다. (ErrMsg: ‘{TableName}에 해당하는 값이 없습니다.’)
  • CharFace: 해당 레코드에서 불러올 캐릭터의 페이셜을 결정한다. (캐릭터의 ID와 연결된 Prefab의 페이셜 모션을 호출한다.)
    • CharPrefab 테이블의 PrefabType에서 Face으로 지정된 프리팹만 호출할 수 있다.
    • 키 입력 시 다음 레코드 값이 동일하면 현재의 애니메이션을 유지한다.
    • 키 입력 시 다음 레코드 값이 동일하지 않으면 다음 레코드의 번호에 지정된 애니메이션을 출력시킨다.
    • Null값을 허용한다.
      • 단, CharPrefab 열이 공란일 때 해당 열의 값이 Null 또는 0이 아니면 오류코드 1을 발생시킨다. (ErrMsg: {RecordNumber} 행의 ‘CharPrefab이 비어있습니다.’)
    • CharPrefab 열의 ID에 없는 값을 입력했을 때 오류코드 2를 발생시킨다. (ErrMsg: ‘{TableName}에 해당하는 값이 없습니다.’)
  • CharFos: 캐릭터가 화면에서 서 있는 위치, 생성되는 속도, 캐릭터의 이동을 결정한다.
    • Null값을 허용한다.
      • 단, CharPrefab 열이 공란일 때 해당 열의 값이 Null 또는 0이 아니면 오류코드 1을 발생시킨다. (ErrMsg: {RecordNumber} 행의 ‘CharPrefab이 비어있습니다.’)
    • CharFos 열의 ID에 없는 값을 입력했을 때 오류코드 2를 발생시킨다. (ErrMsg: ‘{TableName}에 해당하는 값이 없습니다.’)
  • CharName: 해당 레코드에서 나오는 캐릭터의 이름을 결정한다.
    • Null값을 허용한다.
    • CharName 열의 ID에 없는 값을 입력했을 때 오류코드 2를 발생시킨다. (ErrMsg: ‘{TableName}에 해당하는 값이 없습니다.’)
  • ScriptKr: 해당 레코드에 출력시킬 ‘대사’이다.
    • Null값을 허용한다.

아직 기획서가 효율적으로 정규화되어있지는 않지만 1차 기획서 단계에서는 이 정도 내용으로도 충분히 개발이 가능하다고 보았다.

다이얼로그 테이블 설계 단계에서 가장 중요한 Dialog 테이블의 구조는 일단 이 정도로 짜고 넘어가도록 하자.

Dialog 테이블에 입력한 값은 게임 엔진의 DialogScene 프리팹과 연결된다.

16:9 해상도 기준, 해당 프리팹에서 캐릭터 이름창, 대사창 및 편의성 버튼 등의 위치는 아래와 같다.

갈색 영역(CharPos)의 좌표 위치는 프리팹의 절대 좌표를 기준으로 CharPos에 입력한 Const의 Enum을 참조하게 한다.

아래의 갈색 영역의 위치는 대략적인 CharPos의 좌표이다.

(구체적인 좌표의 위치는 실제로 넣어보고 정하도록 한다. 일단은 대략적인 위치만 지정해도 충분하다.)

image 1 5
레퍼런스 게임 ‘우마무스메’를 기준으로, Dialog Scene의 UI 컴포넌트들의 위치를 대략적으로 배치했다.
구체적인 위치의 조정은 기획이 고도화되면서 조정될 예정이다.

  • 다이얼로그 씬(DialogScene)에서는 배경화면, 캐릭터, 캐릭터 이름, 대사창, 편의성 기능 버튼 등의 컴포넌트들이 배치된다.
  • 각 컴포넌트이 배치될 위치는 대략 위의 레퍼런스를 따른다.
  • 편의성 버튼은 우리 게임의 UI/UX 통일성을 해치지 않는 선에서 적절한 크기와 위치에 배치한다.
  • 캐릭터 프리팹은 CharPos 테이블에서 미리 지정한 좌표에서 생성(appear)되거나 사라진다. (disappear) 이는 명령어로 통제한다.
  • 캐릭터가 배치될 위치(CharPos)는 대략 위의 이미지의 위치를 따른다. (정확한 좌표는 실제로 캐릭터 프리팹을 배치해본 뒤에 결정한다.)
    • ※캐릭터 배치(Char Position)에 대한 설명
      • CharPos 3이 기준이다. 캐릭터를 1명만 세울 때는 일반적으로 3번 위치에 세운다.
      • 캐릭터를 2명 이상 배치할 때는 특정 의도가 있지 않는 한 서로 겹치지 않게 배치한다.
        • 캐릭터를 두 명 세울 때는 CharPos 1, CharPos 5에 배치하거나, CharPos 2, CharPos 4에 배치한다.
        • 캐릭터를 세 명 세울 때는 CharPos 1, 3, 5에 세운다.
  • 캐릭터가 배치되는 순서(Layer)는 나중에 배치된 캐릭터가 앞(Front)으로 나온다.
  • 캐릭터는 CharPos에 미리 지정된 좌표 사이를 이동(Transition)할 수 있다.
    • 캐릭터의 이동은 CharPos에서 지정한 각 좌표간에만 이동이 가능하다.
    • 만약 캐릭터를 화면 밖으로 이동시키거나, 화면 밖에서 화면 안으로 들어오게 하는 경우 TopOut, BottomOut, LeftOut, RightOut의 좌표를 활용한다.
  • CharName의 글자수는 로컬라이즈를 고려해 20Byte(10글자)까지는 한 줄로 배치되게 한다.
    • 만약 그 이상 텍스트가 배치되면 글자를 Shrink 처리한다.
    • CharName의 폰트 크기는 12pt 이상이다. (전제조건: ScriptKr보다는 커야 한다.)
    • CharName의 폰트 두께는 SemiBold ~ Bold이다. (전제조건: ScriptKr 보다는 두꺼워야 한다.)
  • ScriptKr의 글자수는 로컬라이즈를 고려해 60Byte(30글자)까지는 한 줄로 배치되게 한다.
  • ScriptKr의 행의 개수는 3줄까지는 글자 크기가 줄어들지 않고 배치되게 한다.
GateFitUI

다이얼로그 씬을 바라보는 카메라의 위치에 관한 테이블이다.

이번 기획에서는 기획목표에 없어서 빠졌지만, 연출 요소 고도화 과정에서 ‘카메라 앵글’에 대한 열도 추가할 예정이다.

그러나 한번 테이블 세팅을 잘 해두면 굳이 장기적인 유지보수가 필요하지 않을 것으로 예상된다.

일단 현 시점에서 필요한 각 열은 아래와 같다.

  • ID: 해당 레코드의 고유 아이디에 해당한다.
    • Primary Key이므로 Null과 중복값을 허용하지 않는다.
  • CameraPosX: 다이얼로그 씬을 바라보는 카메라의 상대좌표 X값을 결정한다.
  • CameraPosY: 다이얼로그 씬을 바라보는 카메라의 상대좌표 Y값을 결정한다.
  • FOV(Field of View): 다이얼로그 씬을 바라보는 시야각을 결정한다. 이에 따라 카메라의 Z값이 종속되어 변화한다.
    • FOV가 높을수록 캐릭터와 배경 등이 가까이 보인다.

다이얼로그 씬에 배치할 ‘캐릭터 프리팹 리소스’와 연관된 테이블이다.

캐릭터 이름 및 캐릭터 프리팹 리소스 경로 등과 밀접한 연관성을 지닌다.

라이브 서비스 시, 매번 캐릭터가 추가될 때마다 캐릭터 프리팹 추가가 필요한 테이블이기도 하다.

  • ID: 해당 레코드의 고유 아이디에 해당한다.
    • Primary Key이므로 Null과 중복값을 허용하지 않는다.
  • #CharName
    • 캐릭터 이름 메모용 열.
  • CharScale: PrefabPath에서 로드한 프리팹의 전역적인 Scale을 지정한다. (0.00~1.00)
  • PrefabType
    • Body: 전신 동작과 관련된 모션은 body로 지정한다.
    • Addon: 전신 동작 중에서 Body 동작에 종속되는 부연 동작을 Addon으로 지정한다.
    • Face: 캐릭터 표정과 관련된 프리팹은 Face로 지정한다.
    • PrefabType이 Null일 때 PrefabPath가 비어있지 않다면, 오류코드 3을 발생시킨다. (ErrMsg: ‘PrefabPath가 비어있지 않다면 반드시 {ColomnName}에 값을 지정해야 합니다.’)
      • 단, PrefabPath가 비어있다면 Null을 허용한다.
  • PrefabPath
    • /PrefabPath 경로에 있는 파일명을 연결하기 위한 열.
    • 입력한 값이 /PrefabPath에 없으면, 오류코드 4를 발생시킨다. (ErrMsg: ‘{ColomnName}에 입력한 값이 해당 리소스 경로에 없습니다.’)
  • #Loop
    • 해당하는 리소스가 Loop용으로 만들어졌다면 ‘O’ 등으로 메모하기 위한 열.

캐릭터의 이동 전반을 컨트롤하는 트랜지션 테이블이다.

캐릭터의 생성과 삭제, 캐릭터의 이동 전반에 관한 내용을 포함한다.

  • ID: 해당 레코드의 고유 아이디에 해당한다.
    • Primary Key이므로 Null과 중복값을 허용하지 않는다.
  • Type: 캐릭터의 등장, 퇴장, 이동에 관한 명령어 리스트.
    • a: 캐릭터를 지정 좌표에서 등장시킨다.
    • d: 캐릭터를 지정 좌표에서 퇴장시킨다.
    • al: 캐릭터가 왼쪽 바깥(LeftOut) -> 오른쪽(CharPos{0})으로 이동하며 등장한다.
    • ar: 캐릭터가 오른쪽 바깥(RightOut) -> 왼쪽(CharPos{0})으로 이동하며 등장한다.
    • ab: 캐릭터가 아래쪽 바깥(BottomOut) -> 위쪽(CharPos{0})으로 이동하며 등장한다.
    • at: 캐릭터가 위쪽 바깥(TopOut) -> 아래쪽(CharPos{0})으로 이동하며 등장한다.
    • dl: 캐릭터가 왼쪽 바깥으로 이동하며 퇴장한다. (CharPos{0} -> LeftOut)
    • dr: 캐릭터가 오른쪽 바깥으로 이동하며 퇴장한다. (CharPos{0} -> RightOut)
    • db: 캐릭터가 아래쪽 바깥으로 이동하며 퇴장한다. (CharPos{0} -> BottomOut)
    • dt: 캐릭터가 위쪽 바깥으로 이동하며 퇴장한다. (CharPos{0} -> TopOut)
  • Time: 해당 Transition의 러닝타임.
    • ms(1000분의 1초) 단위로 기입한 값에 따라 Transition한다.
    • 0ms ~ 5000ms 내의 범위에서 1000ms 단위로 활용한다.
  • CharPosX: CharPos{0} 기준으로, 캐릭터의 상대좌표의 X값.
  • CharPosY: CharPos{0} 기준으로, 캐릭터의 상대좌표의 Y값.

캐릭터 이름 및 캐릭터의 부가 정보에 관한 테이블이다. CharPrefab 테이블과 CharName 열을 두고 1:1 참조하는 관계가 될 수도 있겠지만 아직은 서로 관계를 연결짓지 않았다.

  • ID: 해당 레코드의 고유 아이디에 해당한다. 캐릭터의 개발명이 이에 해당한다.
    • Primary Key이므로 Null과 중복값을 허용하지 않는다.
  • CharName: 화면에 출력할 캐릭터의 이름.
    • 하나의 프리팹에 대해서도 중복값을 허용한다.
  • Faction
    • 미리 Const에 지정된 Faction을 지정하면 해당 캐릭터의 CharName이 다이얼로그에 출력될 때마다 FactionName을 함께 출력시킨다.

위 내용까지 정리된 내용은 아래의 기능을 동작시키기 위해 정리한 최소한의 스펙이다.

  • 3D 캐릭터를 등장/퇴장시킬 수 있다.
  • 캐릭터가 특정 위치에서 등장하거나, 특정 좌표 사이를 이동할 수 있다.
  • 캐릭터의 모션과 표정이 변화할 수 있다.
  • 화면에 캐릭터가 2명 이상 등장할 수 있다.

실제 다이얼로그 시스템 기획에서는 위의 요소 외에도 추가해야할 것이 아주 많다. (특히 연출)

그리고 배경화면을 불러온다든지 BGM이나 SFX를 출력시키는 건 어떻게 할지조차 아직 기획서에 담기지 못한 상태다.

하지만 위의 내용은 최종결과물의 ‘룩앤필’과 비주얼 요소의 ‘뼈대’를 전달함으로써 프로그래머가 최소한의 개발은 들어갈 수 있게 구조를 잡는데 주력했다.

필자는 앞서 ‘버티컬 슬라이스’라는 표현으로 필자의 기획서 작성 방법에 대해 소개했다.

이처럼 뼈대를 바탕으로 필요한 기능을 더해나가는 유연한 개발방법을 ‘동심원 개발(론)’이라고 한다.

(링크)

이 방법은 구현이 완료되었을 때의 비전을 개발 초기부터 공유함으로써 개발이 고도화되어도 방향을 잃지 않게 하는 효율적인 개발 방법이다.

위에 적은 내용도 실제 구현에 필요한 내용을 다 담지 못한, 기획서의 일부분에 불과하며 기획이 고도화될수록 더 많은 트리밍이 필요하다.

필자는 다음 글에서 이어서 개발에 필요한 요소들을 ‘더해나갈’ 예정이다.

#추가 부록 – 해상도 대응 편

모바일 게임이 게임 산업의 주축이 되면서, 다양한 스마트폰 화면의 비율에 게임 화면을 맞춰야할 니즈가 커지게 되었다.

대개 게임을 개발하는 초기 단계에서는 16:9 비율로 게임을 개발하지만, 게임의 막바지 과정에서 22:9나 5:4 등의 ‘특이한’ 해상도 비율에 대응하기 시작하면서 기존의 화면 구성에 문제가 있음을 뒤늦게 깨닫게 되는 경우가 있다.

이러한 문제는 다이얼로그 시스템에서도 예외는 아니다.

해상도 대응에 관해서도 어차피 나중에 필요하게 될테니 미리 시간날 때 기획해두면 도움이 된다.

  • 16:9 외의 해상도 환경에서 게임을 플레이할 때에도 16:9에 준하는 동일한 비주얼 경험을 할 수 있게 한다.

위 구현에 관해서는 ‘다중 해상도 지원 레이아웃 시스템 기획’이라는 이름으로 필자가 과거 작성한 기획안이 있으니 해당 내용으로 갈음하고자 한다.

그밖에도 필자가 다이얼로그 시스템 관련해서 과거 정리한 다양한 문서들이 있다.

굳이 중복으로 같은 내용을 적을 필요는 없으니, 관련한 주제의 글이 있다면 이 문서에 내부 링크를 걸어 해당 글을 확인할 수 있게 하겠다.