8. 通信エラーとボタンの連打に対応する

作ったショップで、連打やコイン不足、通信エラーが起きたときの動きを確かめます。

作ったショップで、購入ボタンを続けて押したり、通信を切ったりしてみましょう。これまで使ってきたプレイヤーで進めます。

処理中にもう一度押してみる

  1. コインを 20 枚以上用意します。足りない場合は冒険をクリアして集めます。
  2. 20 コインでスタミナを 10 回復 を押し、すぐにもう一度押してみます。
  3. 処理中はボタンが無効になり、次の購入を始められないことを確かめます。

コードでは、操作を始めるときに busy を true にし、finally で false に戻しています。ボタンの表示だけでなく、Studio の Run()、SDK の RunWrite() でも処理中の呼び出しを止めています。

購入が完了してボタンが有効になった後に押すと、それは新しい購入になります。

コインが足りないときの表示を確かめる

  1. 購入を繰り返し、コイン残高を 20 枚未満にします。
  2. もう一度購入ボタンを押し、コイン不足のメッセージが表示されることを確かめます。
  3. 失敗した購入でコインが減らず、スタミナも回復していないことを確認します。自然回復で増えた分は除いて比べてください。
  4. 森の探索を始め、冒険の操作は続けられることを確かめます。確認できたらクリアします。

コインやスタミナの不足は、理由を表示して次の操作を受け付けます。

同じ購入を再試行できるようにする

通信が切れたとき、サーバーでは購入が終わっていて、返事だけが届いていないことがあります。そのまま新しい購入を送ると、もう一度コインを使ってしまいます。

そこで、1回の購入に一つのキーを付けます。duplicationAvoider に同じキーを渡して同じ内容を送り直すと、GS2 は完了済みの購入を繰り返さず、その結果を返します。

Unity の再生を止め、使っているコースのファイルで、同名のファイルを置き換えてください。Inspector の参照はそのまま使います。

AdventureStudioView.cs をダウンロードします。

購入を行う Buy() は、次のようになります。purchaseId はクラスのフィールドです。

private string purchaseId;

private async Task Buy()
{
    purchaseId ??= Guid.NewGuid().ToString();
    var request = Gs2ClientHolder.Instance.Gs2.Exchange.Namespace("EnergyProduct")
        .Me(Gs2GameSessionHolder.Instance.GameSession).Exchange();
    var transaction = await request.ExchangeAsync(
        "refill", 1, speculativeExecute: false, duplicationAvoider: purchaseId);
    if (transaction != null) await transaction.WaitAsync(all: true);
    purchaseId = null;
}

AdventurePlay.cs をダウンロードします。AdventurePlayer.cs と AdventureLogin.cs はそのまま使います。

購入を行う BuyRefill() は、次のようになります。purchaseId はクラスのフィールドです。

private string purchaseId;

private async UniTask BuyRefill()
{
    purchaseId ??= Guid.NewGuid().ToString();
    var transaction = await player.Gs2.Exchange.Namespace("adventure-shop").Me(player.Session)
        .Exchange().ExchangeAsync(
            "refill", 1, speculativeExecute: false, duplicationAvoider: purchaseId);
    awaitingResult = true;
    if (transaction != null) await transaction.WaitAsync(all: true);
    purchaseId = null;
}

??= は、値がないときだけ代入する書き方です。通信に失敗しても purchaseId が残るので、再試行には同じキーを使います。購入が完了したら空に戻し、次の購入では新しいキーを作ります。コイン不足で購入できなかったときも、エラー処理で空に戻します。

通信エラー後のボタンは 同じ購入を再試行 に変わります。結果を受け取るまでは、別の冒険や新しい購入を始めず、この購入を送り直せるようにしています。

通信を切ってみる

  1. Unity を再生してログインします。コインを 20 枚以上用意し、スタミナを 10 以下にして、購入前の値を控えます。
  2. パソコンのネットワーク接続を切り、購入ボタンを押します。
  3. 通信エラーが表示され、ボタンが 同じ購入を再試行 に変わるまで待ちます。
  4. ネットワーク接続を戻し、Unity を再生したまま 同じ購入を再試行 を押します。
  5. コインが 20 減り、スタミナが 10 回復することを確かめます。自然回復で増えた分は除いて比べてください。完了すると、ボタンは通常の購入表示に戻ります。

次は、接続した状態で購入ボタンを押した直後に通信を切り、同じように試してみましょう。応答が先に届いて購入が完了した場合は、通常の購入ボタンに戻ります。再試行の表示になった場合だけ、接続を戻して送り直します。

このサンプルは、Unity の再生中にキーを保持します。Play を止めずに試してください。GS2 が重複回避の結果を保存する期間は1時間なので、この練習では通信を戻したらすぐに再試行します。

練習:状況に合うメッセージを考える

「処理中です」「コインが足りません」「通信を確認してください」など、今の状況が分かるメッセージに変えてみましょう。Studio は Run()、SDK は RunWrite() と WriteError() に表示文があります。

次へ:応用編へ進む