3. 퀘스트를 시작하고 보상 받기
목록에 표시된 숲 탐험 을 실제로 플레이할 수 있게 만들어 봅시다. 시작 으로 모험을 떠나고 클리어 로 돌아오면 10코인을 받습니다. 몇 번을 클리어해도 보상은 같고 첫 클리어 보너스는 넣지 않습니다.
클리어 보상은 GS2에 설정하기
보상 수량은 GS2의 퀘스트 설정에서 정합니다. 일반 클리어 보상을 무상 코인 10개로 설정하면 Unity가 클리어를 보고할 때 GS2가 코인을 지급합니다. Unity에서는 잔액 변경에 맞춰 화면을 갱신합니다.
코인은 GS2-Money2의 지갑 에 저장합니다. 지갑을 구분하는 번호를 슬롯 이라고 하며, 이 게임에서는 0을 사용합니다. 이 장에서 Money2 설정을 추가하고 이후에도 같은 지갑을 읽고 씁니다.
퀘스트 완료와 코인 지급은 함께 처리해야 하는 작업입니다. 이런 일련의 처리를 트랜잭션 이라고 합니다. 일반 클리어 보상에 입금을 설정해 두면 Unity는 클리어만 보고하면 됩니다.
설정에서 코인을 지급하는 등의 처리를 획득 액션 이라고 합니다. 다음 단계에서 일반 클리어 보상에 코인 획득 액션을 추가합니다.
따라 하기
통화와 보상 설정하기
Add features 에서 Currency 를 추가합니다.
Quest (Quest) 에서
forest의 Completion rewards 셀을 더블 클릭합니다. 오른쪽의 Add item 을 누르고 추가된 Not set 항목을 엽니다.Action 에서
DepositByUserId를 검색하고money2의 지갑 잔액 추가 액션을 선택합니다. Target resource 는 None 으로 두고 다음 값을 입력합니다.
| 항목 | 값 |
|---|---|
| namespaceName | Currency |
| userId | #{userId} |
| slot | 0 |
#{userId}는 퀘스트를 클리어한 플레이어를 가리킵니다. 실제 플레이어 ID로 바꾸지 말고 그대로 입력합니다.
- depositTransactions 의 Add 를 누르고 생성된 DepositTransaction 을 엽니다.
price는0,currency는 No value 로 두고count에10을 입력합니다. 무상 코인 10개를 지급하는 설정입니다.
첫 클리어 보상과 실패 시 액션은 0개로 둡니다. Publish 에서 서버 배포와 Unity 프로젝트 업데이트를 진행합니다.
시작·클리어·코인 표시 연결하기
Unity의 Gs2 오브젝트에 ProgressHandler와 WalletHandler를 추가합니다. Wallet Handler의 Slot 은 0입니다. AdventureStudioView.cs를 이 장의 코드로 교체하고 Progress 와 Wallet 에 각각 할당합니다. Quests 에는 기존 QuestListHandler를 사용합니다.
퀘스트 조작은 아래 DrawQuestButtons()에 모았습니다. 시작 버튼은 quest.Start(), 클리어 버튼은 progress.Binder.Complete()를 호출합니다. Run()은 처리 중 연속 클릭을 막고 오류를 표시합니다.
잔액과 로딩 상태 표시는 별도 메서드에 있습니다. 아래 링크에서 전체 코드를 다운로드하여 기존 파일을 교체합니다.
private void DrawQuestButtons()
{
var canOperate = !busy && !unresolved && progress.HasValue;
GUI.enabled = canOperate && !progress.Model.InProgress;
foreach (var quest in quests.Binders)
{
GUILayout.Label(quest.DisplayName);
if (GUILayout.Button("시작: " + quest.DisplayName))
{
Run(() => quest.Start());
}
}
GUI.enabled = canOperate && progress.Model.InProgress;
if (GUILayout.Button("클리어"))
{
Run(() => progress.Binder.Complete());
}
GUI.enabled = true;
}이 장의 AdventureStudioView.cs 다운로드
자신의 게임에서는 적을 쓰러뜨리거나 목표 지점에 도착했을 때 이 완료 처리를 호출합니다. 위 코드의 클리어 버튼에 연결된 Run(() => progress.Binder.Complete())가 그 부분입니다. GS2가 보상을 지급하므로 별도로 코인을 더하는 코드는 필요하지 않습니다.
설정 업데이트하기
3장 템플릿을 다운로드하고 Deploy → adventure-game → Update stack 을 열어 Template data 에서 파일을 선택합니다. 이전 장의 리소스도 포함한 전체 템플릿입니다. 변경 내용을 확인하여 적용하고 Update complete 가 될 때까지 기다립니다.
일반 클리어 보상의 depositTransactions에 무상 코인 10개를 지급하도록 설정합니다.
action: Gs2Money2:DepositByUserId
request: |-
{
"namespaceName": "adventure-coin",
"userId": "#{userId}",
"slot": 0,
"depositTransactions": [
{ "price": 0, "currency": "", "count": 10 }
]
}request는 JSON 문자열로 전달합니다. YAML의 |- 아래에 JSON을 작성합니다.
StartAsync()로 퀘스트를 시작하고 EndAsync()로 클리어를 보고합니다. 각 호출이 반환하는 transaction의 WaitAsync(all: true)로 서버 처리가 끝날 때까지 기다립니다. 진행 상태와 잔액은 캐시 변경 알림으로 화면에 반영합니다.
Unity 코드 업데이트하기
다음 두 파일을 Assets에 넣습니다. 같은 이름의 파일이 있으면 교체합니다.
- AdventurePlay.cs: 퀘스트 조작과 화면 표시
- AdventurePlayer.cs: 표시용 데이터의 구독과 해제
기존 AdventurePlay와 Inspector의 Login 설정은 그대로 사용합니다. AdventurePlayer는 코드에서 생성합니다.
데이터 변경에 맞춰 화면 갱신하기
AdventurePlayer는 SubscribeWithInitialCallAsync()로 최초 값과 이후 변경 사항을 받습니다. 예를 들어 지갑이 갱신될 때마다 코인 잔액을 표시할 모델을 교체합니다.
var balance = Gs2.Money2.Namespace("adventure-coin").Me(Session).Wallet(0);
var subscription = await balance.SubscribeWithInitialCallAsync(value => Wallet = value);화면을 그릴 때는 player.Wallet.Summary.Free를 참조합니다. 진행 상태도 같은 방식으로 갱신하므로 시작이나 클리어 후 다시 불러오는 처리는 필요하지 않습니다.
반환값은 구독을 해제할 때 사용합니다. 배포 코드에서는 재생이 끝나 오브젝트가 파괴될 때 Unsubscribe()를 호출합니다.
balance.Unsubscribe(subscription);퀘스트 시작과 클리어 처리하기
버튼은 RunWrite()를 통해 시작과 클리어 처리를 호출합니다. RunWrite()는 연속 클릭을 막고 오류를 표시합니다. awaitingResult는 요청의 응답을 받았음을 나타내며, 그 이후의 오류와 요청 자체가 거절된 경우를 구분합니다.
이 장에서 사용하는 부분은 아래와 같습니다. 이 발췌 코드를 별도 클래스로 추가할 필요는 없습니다.
private async UniTask BeginQuest(string questName)
{
var transaction = await player.Gs2.Quest.Namespace("adventure-quest").Me(player.Session)
.StartAsync("main", questName, force: false, speculativeExecute: false);
awaitingResult = true;
if (transaction != null) await transaction.WaitAsync(all: true);
}
private async UniTask CompleteQuest()
{
var transaction = await player.Gs2.Quest.Namespace("adventure-quest").Me(player.Session)
.Progress().EndAsync(isComplete: true, speculativeExecute: false);
awaitingResult = true;
if (transaction != null) await transaction.WaitAsync(all: true);
}자신의 게임에서는 적을 쓰러뜨리거나 목표에 도착했을 때 CompleteQuest()를 호출합니다. 배포 코드의 클리어 버튼은 RunWrite(CompleteQuest).Forget()으로 호출합니다. 승리 판정에서도 RunWrite()를 거쳐 연속 실행 방지와 오류 표시를 사용합니다. GS2가 보상을 지급하므로 별도의 코인 추가 코드는 필요하지 않습니다.
처리 중에는 시작과 클리어 버튼을 누를 수 없게 합니다. 응답이 오기 전에 같은 처리를 중복 호출하지 않고, 성공하면 화면을 전환합니다. 오류가 반환되면 이유를 표시합니다.
모험을 떠나 봅시다
시작 전 코인 잔액을 기록하고 퀘스트를 시작합니다. 배포 후 보상 설정이 반영되기까지 최대 5분이 걸릴 수 있습니다. 이전 수량이 지급되면 잠시 기다렸다가 새로 시작한 퀘스트로 확인합니다.
| 조작 | 기대하는 결과 |
|---|---|
| 퀘스트 시작 | 진행 중인 퀘스트가 표시됨 |
| 퀘스트 클리어 | 퀘스트가 끝나고 코인이 시작 전보다 10 증가 |
| 같은 퀘스트를 새로 시작하고 클리어 | 코인이 10 더 증가 |
| 퀘스트를 시작하지 않고 클리어 시도 | 코인은 늘어나지 않음 |
통신이 끊겨 결과를 받지 못했다면 성공이나 실패로 단정하지 말고 결과를 확인할 수 없습니다 라고 표시합니다. 바로 클리어 요청을 다시 보내지 마세요.
연습: 설정 바꿔 보기
클리어 보상을 15코인으로 바꾸고 배포해 봅시다. 그 뒤 퀘스트를 새로 시작하고 클리어하여 몇 개가 늘어나는지 확인합니다.
힌트
진행 중인 퀘스트에는 시작 시점의 정보가 저장됩니다. 변경한 보상을 확인하려면 퀘스트를 새로 시작하세요.
다음 장으로 넘어가기 전에
일반 클리어 보상을 10코인으로 되돌려 배포 합니다. 같은 계정으로 숲 탐험을 새로 시작하고 클리어하여 잔액이 10 증가하는지 확인합니다.
