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


# 毎日遊ぶ理由を作る

3日分のログインボーナスと、冒険を3回クリアするミッションを追加します。



ログインした日に報酬を受け取り、冒険を3回クリアすると追加の報酬も受け取れるようにします。ここまで使ってきた学習用プロジェクトとアカウントで進めます。

## 1. ログインボーナスを設定する

1日目は10コイン、2日目は20コイン、3日目は30コインです。日本時間の午前0時に日付が変わり、遊ばなかった日があっても、前回の続きから受け取るルールにします。


**Studio**

**機能を追加**で「ログインボーナス」と「ミッション」を追加します。

**表 → ログインボーナス → ログインボーナスグループ（LoginRewardCollection）** を開き、次の行を作ります。

| 項目 | 入れる値 |
| --- | --- |
| ID | `daily` |
| 進行モード（mode） | `streaming` |
| 日付更新時刻（resetHour） | `15`（UTCの15時＝日本時間の午前0時） |
| 繰り返し（repeat） | `disabled` |
| 取り逃し救済（missedReceiveRelief） | `disabled` |

**ログインボーナス（LoginReward）** に `day1`、`day2`、`day3` の3行を追加し、ボーナスグループをすべて `daily` にします。

各行の **獲得アクション → アイテムを追加 → 未設定** を開き、アクションに `DepositByUserId`（money2）、ターゲットリソースに **なし** を選びます。

| 項目 | 入れる値 |
| --- | --- |
| namespaceName | `Currency` |
| userId | `#{userId}` |
| slot | `0` |

**depositTransactions** に1件追加し、`price` を `0`、`currency` を **値なし** にします。`count` は `day1` が `10`、`day2` が `20`、`day3` が `30` です。


**SDK（Unity）**

<a href="/samples/adventure/extensions/daily-sdk.json" download>ログインボーナスとミッションのテンプレート</a>をダウンロードします。

1. マネージメントコンソールの東京リージョンで **Deploy → スタックリスト → スタックを新規作成** を開きます。
2. スタック名を `adventure-daily` にし、**テンプレートデータ**でダウンロードした JSON ファイルを選び、作成します。
3. 実行状態が **作成完了** になったら、`adventure-login-reward` と `adventure-mission` を使えます。

ログインボーナスの設定は `LoginRewardMaster → Properties → Settings → bonusModels` にあります。

| 項目 | 設定値 |
| --- | --- |
| name | `daily` |
| mode | `streaming` |
| resetHour | `15` |
| repeat | `disabled` |
| missedReceiveRelief | `disabled` |
| rewards | 10、20、30コインの入金を、この順番で3件 |

このスタックは、ログインボーナスとミッションの設定だけを追加します。冒険・コイン・スタミナには、作成済みの `adventure-game` スタックを使います。




## 2. 冒険を3回クリアするミッションを設定する

ミッション用のカウンターを作り、冒険をクリアするたびに1増やします。3回に達したら、ボタンから30コインを受け取れるようにします。


**Studio**

**表 → ミッション → ミッション設定（MissionSetting）** を開き、**行を追加**を押します。リセット時刻を `15`、週次リセット曜日を `sunday`、月次リセット日を `1` にします。

続いて、次の3つの表に行を追加します。

| 表 | ID | 設定 |
| --- | --- | --- |
| ミッションカウンター（MissionCounter） | `clear` | IDだけを入力 |
| ミッショングループ（MissionCollection） | `adventure` | リセット単位を `notReset`、開催スケジュールは空欄 |
| ミッション（Mission） | `clear3` | ミッショングループを `adventure`、進捗カウンターを `clear`、目標値を `3` |

`clear3` の **完了報酬** に `DepositByUserId`（money2）を追加します。設定はログインボーナスと同じで、`namespaceName = Currency`、`userId = #{userId}`、`slot = 0`、`depositTransactions` の `price = 0`、`currency` は値なし、`count = 30` です。

**表 → クエスト（Quest）** を開き、`forest` と `cave` の **通常クリア報酬** に、それぞれ次のアクションを1件追加します。既存のコイン入金は残します。

| 項目 | 入れる値 |
| --- | --- |
| アクション | `IncreaseCounterByUserId`（mission） |
| ターゲットリソース | なし |
| namespaceName | `Mission` |
| userId | `#{userId}` |
| counterName | `clear` |
| value | `1` |

保存し、**反映 → サーバとの差分を確認** からデプロイします。続いて **Unity プロジェクトを更新する** を実行します。


**SDK（Unity）**

先ほど作成した `adventure-daily` に、次のミッションが含まれています。

| 設定 | 値 |
| --- | --- |
| グループ | `adventure`、リセットなし |
| カウンター | `clear`、累計値 |
| ミッション | `clear3`、目標値 `3` |
| 報酬 | `adventure-coin` のスロット `0` に30コイン |

`adventure-game` に使用したテンプレートを開きます。`forest` と `cave` の `contents → completeAcquireActions` に、既存の入金アクションと同じ深さで次の項目を追加します。

```yaml
- action: Gs2Mission:IncreaseCounterByUserId
  request: |-
    {"namespaceName":"adventure-mission","userId":"#{userId}","counterName":"clear","value":1}
```

**Deploy → adventure-game → スタックを更新** を開き、**テンプレートデータ**で編集したファイルを選び、更新します。実行状態が **更新完了** になるまで待ちます。これで、コインの入金とカウンターの加算を、クエストのクリア報酬として実行できます。




## 3. Unity に受け取り画面を追加する


**Studio**

これまでの冒険画面に、ログインボーナスとミッションの受け取りボタンを追加します。表示には引き続き `OnGUI()` を使います。

### Handler を追加する

Unity の再生を止め、Hierarchy の `Gs2` に次のコンポーネントを追加します。

- Login Reward Collection Handler
- Mission Handler
- Mission Counter Handler

### 冒険画面に受け取りボタンを追加する

1. <a href="/samples/adventure/extensions/studio/AdventureStudioView.cs" download>この章の AdventureStudioView.cs</a> をダウンロードし、既存の `Assets/AdventureStudioView.cs` を置き換えます。
2. `Gs2` の **Adventure Studio View** で、新しく増えた **Login Reward**、**Mission**、**Counter** に、上で追加した Handler をそれぞれ割り当てます。**Mission Group** を `adventure`、**Mission Name** を `clear3` にします。
3. 再生してログインすると、スタミナショップの下に、受け取りボタンと進行状況が表示されます。

追加した `DrawDailyRewards()` を、既存の `OnGUI()` から呼んでいます。ボタンを押したときの処理は、冒険の開始・クリアと同じ書き方です。

```csharp
if (GUILayout.Button("今日のログインボーナスを受け取る"))
    Run(() => loginReward.Binder.Receive());

if (GUILayout.Button("ミッション報酬30コインを受け取る"))
    Run(() => mission.Binder.Receive());
```

配布コードでは、読み込み中や処理中の操作を防ぎ、ミッションを達成すると受け取りボタンを押せるようにしています。

Binder の内部でトランザクションの完了まで待つため、画面側で `WaitAsync()` を呼ぶ必要はありません。表示するときは Handler の `Model` を参照します。受け取りや冒険のクリアによる変更も Handler に反映されます。

再生してログインし、**今日のログインボーナスを受け取る** を押します。1日目が「受取済み」になり、冒険画面のコインが10増えます。同じ日にもう一度押しても、コインは増えません。

次に、森の探索を3回クリアします。クリア報酬へのカウンター追加が反映されるまで最大5分かかります。回数が増えない場合は、少し待ってから森の探索を新しく始めてクリアします。累計クリア回数が `3` になると、**ミッション報酬30コインを受け取る** を押せるようになります。受け取ると「受取済み」になり、通常の冒険報酬に加えて30コイン増えます。


**SDK（Unity）**

Unity の再生を止め、空の GameObject を作って `Extensions` と名付けます。<a href="/samples/adventure/extensions/sdk/AdventureDaily.cs" download>AdventureDaily.cs</a> を `Assets/AdventureExtensions` に入れ、`Extensions` に **Adventure Daily** を追加します。**Login** に、シーン内の `AdventureLogin` を割り当て、**Mission Group** を `adventure`、**Mission Name** を `clear3` にします。

配布コードの `Client` は GS2 のクライアント、`Session` はログイン済みのプレイヤーを返すプロパティです。どちらも `AdventureLogin` から取得します。

報酬を受け取るボタンは `RunWrite()` を通して呼びます。ここで一つの要求にキーを付け、`ReceiveLogin()` や `ReceiveMission()` の `requestId` に渡します。通信エラー後は **同じ操作を再試行** で同じ要求を送れます。第8章と同じく、再生を続けたまま、接続を戻したらすぐに試してください。

このサンプルは `OnGUI()` で、冒険画面の右側に受け取りボタンと進行状況を描画します。Game ビューを横に広げ、両方の画面が見えるようにして再生・ログインします。**今日のログインボーナスを受け取る** を押してください。1日目が「受取済み」になり、左側の冒険画面でコインが10増えます。もう一度押しても、同じ日の報酬は増えません。

受取状況とミッションの進行は `SubscribeWithInitialCallAsync()` で購読しています。冒険をクリアしたときも、報酬を受け取ったときも、変更通知で表示が更新されます。

日付が変わると、2日目、3日目の順に受け取れます。受け取りに使っているのは次のAPIです。

```csharp
private async UniTask ReceiveLogin(string requestId)
{
    var transaction = await Client.LoginReward.Namespace(LoginNamespace).Me(Session).Bonus()
        .ReceiveAsync("daily", speculativeExecute: false, duplicationAvoider: requestId);
    if (transaction != null) await transaction.WaitAsync(all: true);
}
```

次に、左側の冒険画面で森の探索を3回クリアします。クリア報酬へのカウンター追加が反映されるまで最大5分かかります。回数が増えない場合は、少し待ってから森の探索を新しく始めてクリアします。右側の累計クリア回数が `3` になったら、**ミッション報酬30コインを受け取る** を押します。受取済みになり、左側のコインが通常の冒険報酬に加えて30増えます。

```csharp
private async UniTask ReceiveMission(string mission, string requestId)
{
    var transaction = await Client.Mission.Namespace(MissionNamespace).Me(Session).Complete(missionGroup)
        .ReceiveRewardsAsync(mission, speculativeExecute: false, duplicationAvoider: requestId);
    if (transaction != null) await transaction.WaitAsync(all: true);
}
```




## 4. 月曜日限定のミッションを追加する

月曜日に冒険を1回クリアすると、30コインを受け取れるミッションを追加します。月曜に達成しておけば、報酬は火曜から日曜までの間にも受け取れます。翌週の月曜0時に達成・受取状態がリセットされ、また挑戦できます。曜日と時刻は日本時間です。

これまでの `clear3` は残し、週替わりのグループ `weekly` に `monday_clear` を追加します。


**Studio**

### 月曜日のスケジュールを作る

**表 → スケジュール基盤 → スケジュール（Schedule）** に、次の行を追加します。開始日時と終了日時はセルを開き、**ローカル（UTC+9）** に切り替えて、日付と時刻を選びます。

| 項目 | 入れる値 |
| --- | --- |
| ID | `monday` |
| スケジュール方式 | `absolute` |
| 開始日時 | `2020-01-01 00:00`（日本時間） |
| 終了日時 | `2099-01-01 00:00`（日本時間） |
| 繰り返し方式 | `weekly` |
| 開始曜日 | `sunday` |
| 開始時刻 | `15` |
| 終了曜日 | `monday` |
| 終了時刻 | `15` |

開始・終了日時には、この週替わりイベントを続ける期間を入れています。その間の毎週月曜日だけを有効にするのが、繰り返しの設定です。曜日・時刻の欄はUTCなので、日本時間の月曜0時〜火曜0時を `sunday 15`〜`monday 15` で指定します。

### 週替わりのミッションを作る

リセット時刻は、日本時間の月曜0時です（ミッション設定の `sunday`・`15`）。

1. **ミッショングループ（MissionCollection）** に `weekly` を追加し、リセット単位を `weekly`、開催スケジュールを `monday` にします。
2. **ミッション（Mission）** に `monday_clear` を追加します。グループを `weekly`、カウンターを `clear`、目標値を `1` にします。完了報酬は `clear3` と同じ30コインです。
3. 保存し、**反映 → サーバとの差分を確認** からデプロイします。続けて **Unity プロジェクトを更新する** を実行します。
4. Unity の再生を止め、`Gs2` の **Adventure Studio View** で **Mission Group** を `weekly`、**Mission Name** を `monday_clear` に変えます。


**SDK（Unity）**

1. <a href="/samples/adventure/extensions/daily-period-sdk.json" download>月曜日限定ミッションのテンプレート</a>をダウンロードします。
2. **Deploy → adventure-daily → スタックを更新** を開き、**テンプレートデータ**でダウンロードしたファイルを選び、更新します。実行状態が **更新完了** になるまで待ちます。
3. Unity の再生を止め、**Adventure Daily** の **Mission Group** を `weekly`、**Mission Name** を `monday_clear` に変えます。

テンプレートには、ログインボーナスと元の `clear3` に加えて、次の設定が入っています。日時を書き換える必要はありません。

| 設定 | 内容 |
| --- | --- |
| スケジュール `monday` | 毎週月曜0時〜火曜0時に有効 |
| グループ `weekly` | 毎週月曜0時に達成・受取状態をリセット |
| ミッション `monday_clear` | カウンター `clear`、目標値 `1`、報酬30コイン |

スケジュールの繰り返し設定は次のとおりです。GS2の曜日・時刻はUTCなので、日本時間の月曜0時〜火曜0時を日曜15時〜月曜15時で指定しています。

```json
"repeatSetting": {
  "repeatType": "weekly",
  "beginDayOfWeek": "sunday",
  "beginHour": 15,
  "endDayOfWeek": "monday",
  "endHour": 15
}
```

ミッションの `challengePeriodEventId` が、このスケジュールを参照します。グループのリセットも `resetType = weekly`、`resetDayOfWeek = sunday`、`resetHour = 15` に設定しています。




追加したミッションの設定が反映されるまで最大5分かかるため、デプロイから5分待って再生・ログインし、森の探索を1回クリアします。月曜日なら「ミッション報酬30コインを受け取れます」と表示されます。火曜〜日曜なら、そのクリアでは達成になりません。

カウンターには既存の累計値を使います。達成判定は冒険のクリアでカウンターが増えたときに行われるため、累計が既に1以上でも、月曜日にもう1回クリアする必要があります。

| タイミング | ミッションの動作 |
| --- | --- |
| 月曜日に冒険をクリア | 達成して30コインを受け取れる |
| 火曜〜日曜 | 新たに達成することはできない。月曜に達成した報酬は受け取れる |
| 次の月曜0時 | 達成・受取状態がリセットされる。受け取らなかった先週の報酬は持ち越せない |

[次へ：アイテムとショップを作る]()



