> For the complete documentation index, see [llms.txt](/ko/llms.txt)


# 2. 퀘스트를 등록하고 목록에 표시하기

첫 퀘스트인 숲 탐험을 등록하고 게임 화면에 표시해 봅니다.



로그인이 되니 이제 모험 목록을 만들어 봅시다. 첫 모험은 **숲 탐험** 입니다. GS2에서는 모험을 퀘스트라고 부르며, 퀘스트 그룹으로 묶어 관리합니다. 이번에는 `main` 퀘스트 그룹에 `forest`라는 ID로 등록하고 화면에 이름을 표시합니다.

## 게임 설정 준비하기

퀘스트 이름이나 보상처럼 개발자가 정하는 게임 설정을 **마스터 데이터** 라고 합니다. 플레이어의 코인 잔액이나 진행 중인 퀘스트 정보는 **유저 데이터** 입니다. 먼저 목록에 표시할 마스터 데이터를 만듭니다.

`forest`는 코드에서 퀘스트를 지정할 때 쓰는 식별자이고, **숲 탐험** 은 플레이어에게 보여 주는 이름입니다. 둘을 분리하면 화면의 이름을 바꾸어도 코드에서는 같은 퀘스트로 다룰 수 있습니다.

목록을 표시하는 데 필요한 설정을 만듭니다. 시작 시 소비량과 보상 항목은 비워 둡니다.

## 따라 하기



**Studio**

### 퀘스트 기능 추가하기

1장에서 사용한 Studio의 `Adventure` 프로젝트를 엽니다. **Add features** 에서 `Quest`를 검색하고 카드의 **Add** 를 누릅니다.

<a href="/images/adventure/studio-2026-11-3/quest-search.jpg" target="_blank" rel="noopener" aria-label="Add features에서 Quest를 검색하고 카드의 Add를 누르는 화면 (새 탭에서 확대)"><img src="/images/adventure/studio-2026-11-3/quest-search.jpg" alt="Add features에서 Quest를 검색하고 카드의 Add를 누르는 화면" loading="lazy"></a>

카드에 **Added** 가 표시될 때까지 기다립니다. 퀘스트에서 사용하는 스케줄 기반 패키지도 함께 추가됩니다.

<a href="/images/adventure/studio-2026-11-3/quest-added.jpg" target="_blank" rel="noopener" aria-label="Quest 카드에 Added가 표시된 상태 (새 탭에서 확대)"><img src="/images/adventure/studio-2026-11-3/quest-added.jpg" alt="Quest 카드에 Added가 표시된 상태" loading="lazy"></a>

### 퀘스트 그룹 만들기

**Tables → Quests → Quest group (QuestCollection)** 을 열고 **Add row** 를 누릅니다. ID 셀을 선택하고 Enter를 누른 뒤 `main`을 입력하고 다시 Enter로 확정합니다. 스케줄은 비워 둡니다.

<a href="/images/adventure/later-chapters/02-quest-group.jpg" target="_blank" rel="noopener" aria-label="ID가 main이고 스케줄이 비어 있는 퀘스트 그룹의 표 (새 탭에서 확대)"><img src="/images/adventure/later-chapters/02-quest-group.jpg" alt="ID가 main이고 스케줄이 비어 있는 퀘스트 그룹의 표" loading="lazy"></a>

### 표시 이름 열 추가하기

게임에서 보여 줄 이름을 담을 열을 추가해 봅시다.

1. **Tables → Quests → Quest (Quest)** 를 열고 **Structure** 탭을 선택합니다.
2. **Shipped as assets** 에서 **Add a column** 을 누릅니다.
3. 열 이름을 `displayName`, 타입을 **string** 으로 설정합니다. **Make it required** 를 켜고 **Add** 를 누릅니다.

<a href="/images/adventure/later-chapters/02-display-name-column.jpg" target="_blank" rel="noopener" aria-label="displayName을 필수 문자열 열로 추가하는 화면 (새 탭에서 확대)"><img src="/images/adventure/later-chapters/02-display-name-column.jpg" alt="displayName을 필수 문자열 열로 추가하는 화면" loading="lazy"></a>

### 숲 탐험 등록하기

**Data** 탭을 열고 **Add row** 로 다음 행을 만듭니다. 셀을 선택하고 Enter를 누르면 문자나 숫자를 편집할 수 있습니다. 퀘스트 그룹 셀을 열어 `main`을 선택합니다. 액션 열은 **No items** 로 둡니다.

| ID | 퀘스트 그룹 | displayName | 시작 시 소비 | 일반 클리어 보상 | 첫 클리어 보상 | 실패 시 액션 |
| --- | --- | --- | --- | --- | --- | --- |
| `forest` | `main` | 숲 탐험 | 0개 | 0개 | 0개 | 0개 |

`displayName`은 표의 맨 오른쪽에 있습니다. 가로로 스크롤하여 **숲 탐험** 을 입력하고 저장합니다.

<a href="/images/adventure/later-chapters/02-quest-display-name.jpg" target="_blank" rel="noopener" aria-label="퀘스트 표를 오른쪽으로 스크롤하여 displayName에 이름을 입력한 상태 (새 탭에서 확대)"><img src="/images/adventure/later-chapters/02-quest-display-name.jpg" alt="퀘스트 표를 오른쪽으로 스크롤하여 displayName에 이름을 입력한 상태" loading="lazy"></a>

### 서버와 Unity에 반영하기

**Publish → Calculate server differences** 를 누르고 GS2에 로그인합니다. 학습용 프로젝트와 Tokyo 리전을 선택한 뒤 변경 내용을 확인하고 배포합니다. 이어서 **Update the Unity project** 를 실행합니다.

### 생성된 퀘스트 목록 표시하기

1. Unity의 `Gs2` 오브젝트에 `QuestListHandler`를 추가하고 **Collection** 을 `main`으로 설정합니다. 아래 코드로 목록을 그리므로 Item Prefab과 Content Parent는 비워 둡니다.
2. `Assets/AdventureStudioView.cs`를 만들고 다음 코드를 붙여 넣습니다.
3. `Gs2` 오브젝트에 `AdventureStudioView`를 추가하고 **Quests** 에 `QuestListHandler`를 할당합니다.
4. 재생하고 로그인하면 **숲 탐험** 이 표시됩니다.

```csharp
using Gs2.Unity.Util;
using System;
using UnityEngine;
using GS2Studio.Generated.Quest;

public sealed class AdventureStudioView : MonoBehaviour
{
    [SerializeField] private QuestListHandler quests;
    private string message = "";

    private void OnEnable()
    {
        if (quests != null) quests.Failed += ShowLoadError;
    }

    private void OnDisable()
    {
        if (quests != null) quests.Failed -= ShowLoadError;
    }

    private void ShowLoadError(Exception error)
    {
        message = "불러오지 못했습니다: " + error.GetType().Name;
    }

    private void OnGUI()
    {
        if (quests == null || Gs2GameSessionHolder.Instance == null || !Gs2GameSessionHolder.Instance.Initialized) return;
        GUILayout.BeginArea(new Rect(20, 100, 650, 650), GUI.skin.box);
        GUILayout.Label(message);
        if (!quests.IsLoaded) { GUILayout.Label("모험 로딩 중"); GUI.enabled = true; GUILayout.EndArea(); return; }
        foreach (var quest in quests.Binders)
        {
            GUILayout.Label(quest.DisplayName);
        }
        GUI.enabled = true;
        GUILayout.EndArea();
    }

}
```

<a href="/samples/adventure/ko/02/AdventureStudioView.cs" download>이 장의 AdventureStudioView.cs 다운로드</a>




**SDK (Unity)**

### 설정 배포하기

<a href="/samples/adventure/ko/02/adventure-game.yaml" download>이 장의 템플릿을 다운로드</a>합니다. 콘솔의 **Deploy → Create stack** 에서 스택 이름을 `adventure-game`으로 지정하고, **Template data** 에서 다운로드한 파일을 선택합니다. 기존 `adventure-login` 스택은 그대로 둡니다.

퀘스트 설정은 다음 부분입니다. 표시 이름을 `metadata`에 문자열로 넣고, Unity에서도 문자열로 읽습니다.

```yaml
Settings:
  version: 2019-05-14
  groups:
    - name: main
      quests:
        - name: forest
          metadata: 숲 탐험
          contents:
            - weight: 1
              completeAcquireActions: []
          consumeActions: []
          firstCompleteAcquireActions: []
          failedAcquireActions: []
```

### 목록 표시 스크립트 추가하기

`Assets/AdventurePlay.cs`를 만들고 다음 코드를 붙여 넣은 뒤 `Adventure` 오브젝트에 추가합니다. Inspector의 **Login** 에 1장의 `AdventureLogin`을 할당합니다. 재생하고 로그인하면 퀘스트 목록이 표시됩니다.

```csharp
using Cysharp.Threading.Tasks;
using System.Collections.Generic;
using Gs2.Unity.Gs2Quest.Model;
using UnityEngine;

public sealed class AdventurePlay : MonoBehaviour
{
    [SerializeField] private AdventureLogin login;
    private readonly List<EzQuestModel> quests = new List<EzQuestModel>();
    private bool ready;
    private string message = "로딩 중";

    private void OnGUI()
    {
        if (login == null || login.Session == null) return;
        GUILayout.BeginArea(new Rect(20, 210, 650, 650), GUI.skin.box);
        GUILayout.Label(message);
        if (ready)
        {
            foreach (var quest in quests)
            {
                GUILayout.Label(quest.Metadata + " (" + quest.Name + ")");
            }
        }
        GUI.enabled = true;
        GUILayout.EndArea();
    }

    private void Start() => LoadQuests().Forget();

    private async UniTask LoadQuests()
    {
        try
        {
            await UniTask.WaitUntil(() => login.Session != null,
                cancellationToken: this.GetCancellationTokenOnDestroy());
            var group = login.Gs2.Quest.Namespace("adventure-quest").QuestGroupModel("main");
            await foreach (var item in group.QuestModelsAsync())
            {
                if (item != null) quests.Add(item);
            }
            ready = true;
            message = quests.Count == 0 ? "모험이 없습니다" : "불러왔습니다";
        }
        catch (System.OperationCanceledException) { }
        catch (System.Exception error)
        {
            message = "불러오지 못했습니다: " + error.GetType().Name;
        }
    }
}
```

<a href="/samples/adventure/ko/02/AdventurePlay.cs" download>AdventurePlay.cs 다운로드</a>






## 목록 확인하기

게임을 실행하고 로그인하여 **숲 탐험** 이 하나 표시되는지 확인합니다.

## 연습: 설정 바꿔 보기

이름을 **숲 순찰** 로 바꿔 봅시다. Studio에서는 배포와 Unity 에셋 업데이트를 진행하고, SDK에서는 설정을 반영한 뒤 퀘스트를 다시 불러옵니다. 화면의 이름도 바뀌었나요? 배포 후 변경한 설정이 게임에 실제로 반영되기까지 최대 5분이 걸릴 수 있습니다. 이전 이름이 보이면 잠시 기다렸다가 Unity의 재생을 중지하고 다시 재생하여 확인합니다.

## 다음 장으로 넘어가기 전에

연습에서 표시 이름을 바꾸었다면 **숲 탐험** 으로 되돌려 반영합니다. 그룹은 `main`, 식별자는 `forest`로 두고 소비와 보상은 아직 설정하지 않은 상태로 진행합니다.

[다음: 퀘스트를 시작하고 보상 받기]()



