6
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

PlayFabで登録したハイスコア(Statistics)がランキング(Leaderboard)にすぐ反映されない原因と対策

Last updated at Posted at 2018-12-23

前提と問題

UnityゲームのバックエンドにPlayFabを使って、スコアランキング機能の実装を試みた。

この辺を見て、1ゲームが終わった直後にUpdatePlayerStatistics()でハイスコア(PlayerStatistics)を更新して、そのレスポンスが返ってきた後にGetLeaderboard()でランキング(Leaderboard)を取得したのだけど、今送信したばかりのスコアがランキングに反映されていない。
しかし、暫くしてからGetLeaderboard()したら反映されているし、PlayFab管理画面でも更新されている。

Unity仮想コード

void Start()
{
    PlayFabClientAPI.UpdatePlayerStatistics(
        new UpdatePlayerStatisticsRequest() {
            Statistics = new List<StatisticUpdate>() {
                new StatisticUpdate() {
                    StatisticName = myStatisticName,
                    Value = myScore
                }
            }
        }, OnUpdatePlayerStatisticsSuccess, OnFailure);
}

void OnUpdatePlayerStatisticsSuccess(UpdatePlayerStatisticsResult result)
{
    GetLeaderboard();
}

void GetLeaderboard()
{
    PlayFabClientAPI.GetLeaderboard(
        new GetLeaderboardRequest() {
            StatisticName = myStatisticName,
        }, OnGetLeaderboardSuccess, OnFailure);
}

void OnGetLeaderboardSuccess(GetLeaderboardResult result)
{
    var entries = result.Leaderboard; // これにmyScoreが反映されていないことがある

    // entries を画面に表示する処理など
}

環境

  • Unity 2018.2.19f1
  • PlayFab

forumを検索してみる(英語)

StatisticsをUpdateしてからLeaderboardが最新の状態になるまでに1秒かそれ以上かかるので、Cloud ScriptでStatisticsをUpdateしつつLeaderboardのUpdateを行って、Cloud Scriptが返ってきた後でLeaderboardのクライアントクエリを取得するのがオススメとのこと。
けどserverのAPIリファレンス見てもLeaderboardをUpdateするメソッドが見つからない。

この辺には数秒(具体的な数字としては2秒)待つと書いてある。
えー。

対策

  • スコア確定次第なるはやでUpdatePlayerStatistics()を呼び出し、GetLeaderboard()まで時間が空くような画面、UXデザインにする
  • 以下のいずれかの場合、未反映状態とみなして(少し時間を空けてから)取得し直す
    • 取得したLeaderboardの範囲内に自身のPlayFabIdのLeaderboardEntryがある、かつスコアが更新されているはずなのに更新されていない
    • 取得範囲内に自身のLeaderboardEntryがないが、LeaderboardEntryの個数が取得Request数に満たない(反映済みなら自身のLeaderboardが含まれるはず)
    • 取得範囲内に自身のLeaderboardがないが、自身のスコアが範囲内の最低点より高い(同上)
  • 指定PlayFabId(大体は自分)を中心にしたLeaderboardを返すGetLeaderboardAroundPlayer()なんてのもあり、こちらを使う場合は自身のLeaderboardEntryが必ず含まれるはずなので、前者の条件だけで良い

Unity仮想コード

さっきと同じ処理のところは割愛

void OnUpdatePlayerStatisticsSuccess(UpdatePlayerStatisticsResult result)
{
    StartCoroutine("WaitAndGetLeaderboard", 2f);
}

void WaitAndGetLeaderboard(float waitSeconds)
{
    yield return new WaitForSeconds(waitSeconds);
    GetLeaderboard();
}

void OnGetLeaderboardSuccess(GetLeaderboardResult result)
{
    var entries = result.Leaderboard;
    var myEntry = entries.Find(_entry => _entry.PlayFabId == myPlayFabId);
    if (myEntry != null && myEntry.StatValue < myScore
        || myEntry == null && entries.Count < requestedEntriesCount
        || myEntry == null && entries[entries.Count - 1].StatValue < myScore)
    {
        StartCoroutine("WaitAndGetLeaderboard", 1f);
        return;
    }

    // entries を画面に表示する処理など
}

Cloud Scriptで対処する場合

本来は、クライアントでのチートを防止するため、UpdatePlayerStatistics()ではなくCloud ScriptでStatisticsをUpdateするのが良いそうで(そもそも意図的にAllow client to post player statisticを設定しないとUpdatePlayerStatistics()のリクエストは無効)
それを踏まえると、1個目のforum検索結果の

Cloud ScriptでStatisticsをUpdateしつつLeaderboardのUpdateを行って、Cloud Scriptが返ってきた後でLeaderboardのクライアントクエリを取得するのがオススメとのこと。

を「StatisticsをUpdateしてからLeaderboardのUpdateを待って」と読み替えてCloud Scriptを実装すると良いような気が。
APIの単位としてはそれが正解だと思うのですが、レスポンスが返ってくるのに毎度2秒以上待つのも変なので…悩ましい。

もっと良い手があれば誰か教えてください!

せっかくなので

そんなハイスコア機能を組み込んだゲーム、WebGL版をunityroomさんで、Android版をGoogle Play Storeで公開しているので、良かったら遊んでってください。
unityroomさんのunity1週間ゲームジャムに投稿後、今回の手法でハイスコア機能を追加したものとなります。
icon2.png
https://unityroom.com/games/10to10
https://play.google.com/store/apps/details?id=com.zurachu.TenToTen

6
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?