본문 바로가기
게임개발/가마수트라

대화를 프로그래밍하는 기술

by 아수랑 2023. 12. 29.
728x90
분야: 기획, 프로그래밍 / 6분 읽기
작성자: Kenneth Harper


대화처럼 단순한 것을 멋지게 표현하는 것은 꽤나 어려운 일이므로, 프로그래밍 렌즈를 통해 조정 가능하고 매력적인 UI 기반 대화 시스템을 만드는 여정에 여러분을 초대합니다.



첫 번째 구성 요소는 단어 자체와 이를 어떻게 저장할지 결정하는 것입니다. 제가 프로그래머이자 파트타임 아티스트로 참여하고 있는 게임 Rockin' Racket의 경우 Ink를 사용했습니다. Ink는 Inkle Studios에서 개발한 내러티브 스크립팅 언어입니다. 저는 이 언어에 대한 전문가는 아니므로 자세한 내용을 알고 싶으시면 여기에서 읽어보시기 바랍니다.

그러나 Ink 파일의 일반적인 개념은 텍스트 파일을 대화로 구성하는 것으로, 각 텍스트 줄이 대화의 한 줄이지만 다음 줄에 대한 여러 가지 옵션, 대화의 섹션 및 가변 시스템에 대한 구체적인 사용 사례를 추가할 수 있다는 장점이 있습니다. 또한 잉크 파일은 종속성을 허용하므로 개발자는 'INCLUDE' 키워드를 통해 다른 변수를 사용하는 잉크 파일을 가질 수 있습니다. 제 작업의 핵심은 같은 회사에서 개발한 잉크-유니티 통합 패키지를 통해 간소화된 Unity용 스크립트 내에서 프로그래밍 방식으로 잉크 파일을 읽는 것이었습니다.

잉크 예제 파일.png


이 패키지는 잉크 파일을 읽을 수 있는 JSON 파일로 컴파일하여 스크립트 내에서 스토리 오브젝트로 변환할 수 있습니다. 이러한 스토리 객체에는 현재 줄, 변수, 그리고 "#태그이름: 태그값"으로 표시되는 태그라는 매우 편리한 줄별 변수 유형이 저장됩니다. 각 태그는 각 줄에 대해 업데이트되는 스토리 속성의 일부입니다. 이제 잉크 파일과 그 기능에 대해 더 잘 알게 되었으니 이제 제가 Rockin Racket을 위해 개발한 대화 시스템에 대해 설명하겠습니다.

다이얼로그 코드


제가 개발한 대화 시스템은 씬에 넣어도 문제없이 작동할 수 있는 완전히 독립적인 작품이 되어야 했습니다. 이를 위해 트리거와 매니저로 구성된 시스템을 만들었는데, 트리거에는 잉크 파일이 첨부되어 있고, 트리거가 트리거되면 잉크 파일을 매니저 오브젝트로 전송합니다. 관리자 객체는 대화의 그래픽 디스플레이와 프로그래밍 백엔드를 모두 처리합니다. 플레이어가 대화를 볼 수 있도록 UI는 메인 대화 패널로 구성되며, 왼쪽 상단에는 이름 태그가, 패널 중앙에는 대화 줄이, 하단에는 대화 선택 버튼이, 오른쪽 중앙에는 대화 계속 버튼이 표시됩니다. 메인 패널 뒤에는 두 개의 캐릭터 스프라이트가 있는데, 왼쪽의 작은 스프라이트는 플레이어 캐릭터를 나타내고 화면 오른쪽 전체에 걸쳐 있는 큰 스프라이트는 대화 중인 캐릭터입니다.

반응형


반응적이고 역동적인 시스템을 구현하기 위해 잉크 태그를 혼합하여 이름표를 업데이트하고, 화자의 감정과 대화창 레이아웃을 업데이트했습니다. Unity에서 잉크 태그를 사용하려면 먼저 스토리 오브젝트에서 잉크 태그를 처리해야 합니다. 다행히도 각 태그는 실제로 잉크에서 # 기호 뒤에 오는 문자열일 뿐이며, 한 줄에 있는 모든 태그는 스토리 오브젝트의 currentTags 속성을 통해 문자열 목록으로 검색할 수 있습니다. 하지만 이 구조는 태그 값을 사용하기 전에 먼저 태그 값을 분할하여 처리해야 한다는 것을 의미합니다. 태그를 분할하려면 Unity에 내장된 "split" String 함수를 사용하여 분할된 문자열을 길이 2 배열에 저장하면 됩니다. 인덱스 0에 있는 첫 번째 요소는 태그의 키가 되고 인덱스 1에 있는 두 번째 요소는 값이 됩니다. 그런 다음 태그 키에 따라 서로 다른 동작을 설정할 수 있습니다. 태그 처리를 구현한 후 내러티브 작가와 협력하여 화자, 인물, 레이아웃의 세 가지 태그가 있는지 확인했습니다.


레이아웃 태그는 레이아웃을 업데이트하는 데 사용되며, 이는 Unity 애니메이터를 간단히 호출하는 것입니다. Unity의 애니메이터는 프레임 단위로 애니메이션을 임포트하는 것 외에도 다양한 용도로 사용할 수 있지만, 레이아웃을 저장하는 데 적합한 특정 오브젝트 위치 세트를 저장하는 데 쉽게 사용할 수 있습니다. 다른 태그는 더 흥미롭습니다.

스피커 태그는 말하는 캐릭터의 이름으로, 캐릭터에 따라 태그에 지정된 값으로 이름 태그를 업데이트하고, Rockin' Racket의 각 주인공은 팔레트를 정의하는 시그니처 색상이 있기 때문에 말하는 캐릭터와 일치하도록 이름 태그의 배경색을 업데이트합니다.

초상화 태그는 가장 복잡하지만 비교적 간단합니다. 우선 초상화 태그를 변경하는 각 줄에는 플레이어 캐릭터 스프라이트와 다른 캐릭터 스프라이트에 각각 하나씩 총 2개의 초상화 태그가 있어야 합니다. 하지만 각 태그는 문자열이기 때문에 프로그래밍 언어의 일반 변수와 달리 두 개의 다른 세로 태그가 처리됩니다. 어떤 스프라이트 애니메이터를 사용할지 결정하기 위해 문자열의 첫 단어가 플레이어 캐릭터의 이름인 "harvey"인지 확인합니다. 이 경우 플레이어 캐릭터 스프라이트를 업데이트하는 애니메이터가 사용되지만, 그렇지 않은 경우 비플레이어 캐릭터 스프라이트를 업데이트하는 애니메이터가 사용됩니다. 각 애니메이터에는 레코딩된 애니메이션 목록이 있으며, 키가 "portrait"인 태그의 태그 값은 애니메이션의 이름이며, 관리자는 애니메이터에게 태그 값을 재생하도록 지시하여 Unity가 다음에 애니메이션할 내용을 지시할 수 있도록 합니다.

가장 쉬운 부분은 대화의 다음 줄을 검색하는 것으로, 스토리 오브젝트에서 "nextLine" 메서드를 간단히 호출하면 됩니다. 반환 값은 해당 대화 줄이 포함된 문자열이며, 텍스트 메시 오브젝트를 업데이트하여 검색된 값을 표시할 수 있습니다. 하지만 이 메서드를 호출하면 스토리도 함께 이동하므로 이 메서드를 호출할 때마다 태그를 처리해야 합니다.

플레이어 입력을 허용하기 위해 스토리 오브젝트에는 특정 줄에서 선택이 가능한지 여부와 그 수를 결정할 수 있는 currentChoices 속성도 있습니다. 진행 중일 때마다 이 메서드를 호출하면 해당 대사가 단순한 대화 연속인지, 아니면 선택 옵션을 표시해야 하는지 확인할 수 있습니다. 선택 옵션을 구현하는 것도 매우 간단합니다. 각 선택 항목은 currentChoices 목록에서 해당 위치에 해당하는 인덱스로 설정되기 때문입니다. 그런 다음 각 선택 항목을 인덱스로 설정하면 플레이어가 어떤 선택을 할지 결정하고 플레이어 선택 항목의 인덱스를 입력으로 사용하여 스토리 객체에서 "chooseChoiceIndex" 메서드를 호출할 수 있습니다. 그 후 "nextLine"을 호출하기만 하면 스토리가 올바른 대화 트리로 진행됩니다! 전체적으로 이 시스템은 적응력 있는 워크플로를 만들고 흥미로운 UI 요소를 만들 수 있도록 도와줍니다!


* 원문:

 

The Art to Programming Conversation

Something as simple as talking can be quite the challenge to express, so I invite you on the journey of using Ink to make an adjustable, engaging UI-based dialogue system through a programming lens.

www.gamedeveloper.com

 

* 게임 사이트: https://www.instagram.com/rockinracket/

 

// 오역이 있을 수 있습니다. 잘못된 번역은 댓글로 알려주세요.

반응형
LIST

댓글