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


# 아이템과 상점 만들기

모험 보상에 회복약을 추가하고 사용·구매 버튼을 만듭니다.



숲 탐험을 클리어하면 코인과 함께 회복약을 하나 받도록 만듭니다. 회복약 하나를 사용하면 스태미나가 5 회복되며 상점에서는 20코인으로 하나를 살 수 있습니다.

## 1. 회복약 등록하기

아이템은 종류별 보유 수량을 관리하는 Simple Inventory에 저장합니다. 회복약의 ID는 `potion`입니다.


**Studio**

1. **Add features** 에서 **Items** 를 추가합니다.
2. **Tables → Item** 에 행을 추가하고 ID를 `potion`으로 설정합니다. 보유 수량은 플레이어 데이터이므로 이 표에는 입력하지 않습니다.
3. **Publish → Calculate server differences** 에서 배포한 뒤 **Update the Unity project** 를 실행합니다.
4. <a href="/samples/adventure/ko/extensions/items-studio.json" download>회복약 사용·구매 템플릿</a>을 다운로드합니다.


**SDK (Unity)**

<a href="/samples/adventure/ko/extensions/items-sdk.json" download>회복약 저장·사용·구매 템플릿</a>을 다운로드합니다. 다음 설정이 들어 있습니다.

| 설정 | 값 |
| --- | --- |
| Inventory 네임스페이스 | `adventure-inventory` |
| Simple Inventory | `Inventory` |
| 아이템 | `potion` |
| 사용·구매용 Exchange 네임스페이스 | `adventure-item-actions` |




다운로드한 템플릿을 관리 콘솔에서 배포합니다.

1. Tokyo 리전에서 **Deploy → Stack list → Create stack** 을 엽니다.
2. 스택 이름을 `adventure-items`로 지정하고 **Template data** 에서 다운로드한 JSON 파일을 선택합니다.
3. **Create** 를 누르고 **Create complete** 가 될 때까지 기다립니다.

이제 `adventure-item-actions`에 다음 두 교환 설정이 만들어집니다.

| 교환 이름 | 소비 | 획득 |
| --- | --- | --- |
| `use_potion` | 회복약 1개 | 스태미나 5 |
| `buy_potion` | 무상 코인 20개 | 회복약 1개 |

## 2. 숲 탐험 보상에 회복약 추가하기


**Studio**

**Tables → Quests → Quest** 에서 `forest`를 엽니다. **Completion rewards → Add item → Not set** 에서 다음 액션을 추가합니다. 코인 입금과 앞 페이지에서 추가한 미션 카운터 증가 액션은 그대로 둡니다.

| 항목 | 입력할 값 |
| --- | --- |
| 액션 | `AcquireSimpleItemsByUserId`(inventory) |
| 대상 리소스 | None |
| namespaceName | `Inventory` |
| inventoryName | `Inventory` |
| userId | `#{userId}` |

**acquireCounts** 에 항목을 하나 추가하고 `itemName`은 `potion`, `count`는 `1`로 설정합니다. 저장하고 서버에 배포한 뒤 Unity 프로젝트도 업데이트합니다.


**SDK (Unity)**

`adventure-game`에 사용한 템플릿을 엽니다. `forest`의 `contents → completeAcquireActions` 끝에 다음 항목을 추가합니다. 코인 입금과 미션 카운터 증가 항목은 그대로 둡니다.

```yaml
- action: Gs2Inventory:AcquireSimpleItemsByUserId
  request: |-
    {"namespaceName":"adventure-inventory","inventoryName":"Inventory","userId":"#{userId}","acquireCounts":[{"itemName":"potion","count":1}]}
```

**Deploy → adventure-game → Update stack** 에서 **Template data** 에 수정한 파일을 선택해 업데이트합니다. **Update complete** 가 될 때까지 기다립니다.




## 3. Unity에 수량과 사용·구매 버튼 추가하기

Unity의 재생을 멈춥니다. 다음 파일을 추가하면 오른쪽 화면이 회복약 수량과 조작 버튼으로 바뀝니다. 왼쪽 모험 화면은 그대로 사용합니다.


**Studio**

빈 GameObject를 만들고 `Extensions`라고 이름 붙입니다. 모험 화면의 로그인 보너스와 미션 보상 버튼은 그대로 둡니다.

<a href="/samples/adventure/ko/extensions/studio/AdventureItems.cs" download>AdventureItems.cs</a>를 `Assets/AdventureExtensions`에 넣고 `Extensions`에 **Adventure Items** 를 추가합니다. 로그인된 `Gs2ClientHolder`와 `Gs2GameSessionHolder`를 사용합니다.


**SDK (Unity)**

`Extensions`의 **Adventure Daily** 체크를 해제합니다.

<a href="/samples/adventure/ko/extensions/sdk/AdventureItems.cs" download>AdventureItems.cs</a>를 `Assets/AdventureExtensions`에 넣고 `Extensions`에 **Adventure Items** 를 추가합니다. **Login** 에 씬의 `AdventureLogin`을 할당합니다.




Game 뷰를 넓혀 왼쪽 모험 화면과 오른쪽 회복약 화면이 모두 보이게 합니다. 재생하고 로그인한 뒤 회복약 수량이 표시되는지 확인합니다.

`SimpleInventory("Inventory").SimpleItem("potion")`을 구독해 수량을 표시합니다. 초기값과 이후 변경을 같은 콜백으로 전달받습니다.

```csharp
var item = Client.Inventory.Namespace(InventoryNamespace).Me(Session)
    .SimpleInventory("Inventory").SimpleItem("potion");
var id = await item.SubscribeWithInitialCallAsync(value => potion = value);
```

왼쪽에서 숲 탐험을 시작하고 클리어합니다. 오른쪽 회복약이 하나 늘고 왼쪽 코인도 늘면 보상이 추가된 것입니다. 배포 후 보상 변경이 적용되기까지 최대 5분이 걸릴 수 있습니다. 코인만 늘면 잠시 기다린 뒤 숲 탐험을 새로 시작해 클리어합니다. 코인과 스태미나는 계속 왼쪽 모험 화면에서 확인합니다.

## 4. 회복약 사용하기

스태미나가 15 이하일 때 **회복약 1개로 스태미나 5 회복** 을 누릅니다. 회복약이 하나 줄고 스태미나가 5 늘어납니다. 도중에 자연 회복이 일어나면 그만큼도 더해집니다.

사용 버튼은 `RunWrite(id => Exchange("use_potion", id))`로 다음 교환 처리를 호출합니다. `requestId`는 통신 오류 후 같은 작업을 재시도하기 위한 키입니다.

```csharp
private async UniTask Exchange(string rate, string requestId)
{
    var transaction = await Client.Exchange.Namespace("adventure-item-actions").Me(Session).Exchange()
        .ExchangeAsync(rate, 1, speculativeExecute: false, duplicationAvoider: requestId);
    if (transaction != null) await transaction.WaitAsync(all: true);
}
```

템플릿은 소비에 `Gs2Inventory:ConsumeSimpleItemsByUserId`, 획득에 `Gs2Stamina:RecoverStaminaByUserId`를 지정합니다. 회복약이 0개일 때도 사용 버튼을 눌러 봅니다. 수량 부족이 표시되고 스태미나는 늘지 않습니다.

## 5. 코인으로 회복약 구매하기

코인을 20개 이상 준비하고 **20코인으로 회복약 1개 구매** 를 누릅니다. 코인이 20개 줄고 회복약이 하나 늘어납니다.

구매 버튼도 같은 교환 API를 사용하며 교환 이름만 `buy_potion`으로 바꿉니다.

```csharp
RunWrite(id => Exchange("buy_potion", id)).Forget();
```

구매 시 `Gs2Money2:WithdrawByUserId`의 `slot = 0`, `withdrawCount = 20`, `paidOnly = false`로 코인을 소비하고, `Gs2Inventory:AcquireSimpleItemsByUserId`로 `potion` 하나를 지급합니다.

재생을 멈췄다가 다시 시작하고 같은 플레이어로 로그인합니다. 구매한 회복약이 남아 있는지 확인한 뒤 다음 단계에서 캐릭터를 추가합니다.

[다음: 캐릭터를 모으고 성장시키기]()



