(:3[kanのメモ帳]

個人ゲーム開発者kan.kikuchiのメモ的技術ブログ。月木更新でUnity関連がメイン。

(:3[kanのメモ帳]



Unity+PlayFabでユーザ名の更新とランキングの実装【Unity】【PlayFab】


このエントリーをはてなブックマークに追加



この記事でのバージョン
Unity 2018.4.8f1
PlayFab SDK 2.77.191029


はじめに

今回はUnityでPlayFabを使ってユーザ名の更新とランキングの実装してみようという感じの記事です!


ちなみに、PlayFabとはなんぞや?という方は以下の記事を参照の事。

ざっくり言うとサーバーサイドが関わる事を楽して実装出来るサービスです。



しかも、無料で始める事も可能ですし、有料プランでも1000MAUまでは無料

「ユーザが全然増えないのにお金だけ払う」みたいな事がありません。

なので個人開発でも使い始めやすいですし、Microsoftのサービスという安心感まであります。



なお、本記事は以下の導入やログイン処理が済んでいる前提になりますので、あしからず。





事前準備

まずランキングを実装する前にクライアントから情報を送信する許可を設定します。


その設定はWindow/PlayFab/Editor Extensionsで開けるウィンドウ右上の

GAME MANAGERをクリックすると開ける、ブラウザ上の設定用のページで行います。

f:id:kan_kikuchi:20200105044438j:plain
f:id:kan_kikuchi:20200105044447j:plain


設定箇所は左上の歯車のマークにある「タイトルの設定」を押した先にある

f:id:kan_kikuchi:20200114044826j:plain


API機能「クライアントにプレイヤー統計情報のポストを許可する」です。

ここにチェックを入れれば事前準備です。

f:id:kan_kikuchi:20200114044836j:plain



ランキング作成

次にランキングの作成です。これも引き続きブラウザ上で行います。

作成場所は左側のランキングを選択した後にある「新しいランキング」ボタンです。

f:id:kan_kikuchi:20200114045459j:plain


各設定を行った後、保存ボタンを押すと新しいランキングが作成される感じです。

f:id:kan_kikuchi:20200114045521j:plain


なお、リセット頻度がランキングに登録されたスコアを初期化する頻度で、

(手動の場合は自動ではスコアは初期化されない)

f:id:kan_kikuchi:20200114045550j:plain


集計方法がランキングの順位付けの方法の事になります。

f:id:kan_kikuchi:20200114045559j:plain


ちなみに作成したランキングはブラウザ上でもランキングを確認可能ですし、

登録されているスコアを削除したり、ランキング自体を手動リセットする事も可能です。

f:id:kan_kikuchi:20200115115451j:plain



ユーザ名の更新

PlayFabは各ユーザに名前を設定する事が出来るので、今度はその実装方法についての解説です。

なお、IDで識別出来るので名前を設定しなくてもランキングを利用する事は可能です。

f:id:kan_kikuchi:20200115104348j:plain


肝心のユーザ名の更新方法ですが、

以前の記事で紹介したような感じでログイン処理を先に行います。



そしてその後、UpdateUserTitleDisplayNameRequestのインスタンスを生成し、

PlayFabClientAPI.UpdateUserTitleDisplayNameにそれプラス、成功時と失敗時のデリゲートを渡すだけ。


なお、新規で名前をつける時でも名前を変更する時でも同じ処理で問題ありません。

using System.Collections.Generic;
using PlayFab;
using PlayFab.ClientModels;
using UnityEngine;
using UnityEngine.UI;

/// <summary>
/// ランキングのサンプル
/// </summary>
public class RankingSample : MonoBehaviour {

  [SerializeField]
  private Text _nameText = default;

  //=================================================================================
  //ユーザ名
  //=================================================================================

  /// <summary>
  /// ユーザ名を更新する
  /// </summary>
  public void UpdateUserName() {
    //ユーザ名を指定して、UpdateUserTitleDisplayNameRequestのインスタンスを生成
    var request = new UpdateUserTitleDisplayNameRequest{
      DisplayName = _nameText.text
    };

    //ユーザ名の更新
    Debug.Log($"ユーザ名の更新開始");
    PlayFabClientAPI.UpdateUserTitleDisplayName(request, OnUpdateUserNameSuccess, OnUpdateUserNameFailure);
  }
  
  //ユーザ名の更新成功
  private void OnUpdateUserNameSuccess(UpdateUserTitleDisplayNameResult result){
    //result.DisplayNameに更新した後のユーザ名が入ってる
    Debug.Log($"ユーザ名の更新が成功しました : {result.DisplayName}");
  }

  //ユーザ名の更新失敗
  private void OnUpdateUserNameFailure(PlayFabError error){
    Debug.LogError($"ユーザ名の更新に失敗しました\n{error.GenerateErrorReport()}");
  }

}


実際に使ってみると以下のような感じで、

名前を送信するとブラウザ上での表記が変わっているのが分かると思います。

f:id:kan_kikuchi:20200115103706g:plain


ちなみに、名前が2文字以下だとエラーが出るようです。

f:id:kan_kikuchi:20200115103358j:plain



スコア送信

スコアを送信し、ランキングに登録する方法ですが、

ユーザ名の更新と同様にログイン処理を先に行います。


そしてその後、StatisticUpdateという更新用のインスタンスを生成し、

それを使ってさらにUpdateUserDataRequestのインスタンスを生成、

最後にPlayFabClientAPI.UpdatePlayerStatisticsにそれプラス、成功時と失敗時のデリゲートを渡すだけ。

using System.Collections.Generic;
using PlayFab;
using PlayFab.ClientModels;
using UnityEngine;
using UnityEngine.UI;

/// <summary>
/// ランキングのサンプル
/// </summary>
public class RankingSample : MonoBehaviour {

  [SerializeField]
  private Text _scoreText = default;

  //=================================================================================
  //スコア
  //=================================================================================

  /// <summary>
  /// スコア(統計情報)を更新する
  /// </summary>
  public void UpdatePlayerStatistics() {
    //UpdatePlayerStatisticsRequestのインスタンスを生成
    var request = new UpdatePlayerStatisticsRequest{
      Statistics = new List<StatisticUpdate>{
        new StatisticUpdate{
          StatisticName = "ランキングサンプル",   //ランキング名(統計情報名)
          Value = int.Parse( _scoreText.text), //スコア(int)
        }
      }
    };

    //ユーザ名の更新
    Debug.Log($"スコア(統計情報)の更新開始");
    PlayFabClientAPI.UpdatePlayerStatistics(request, OnUpdatePlayerStatisticsSuccess, OnUpdatePlayerStatisticsFailure);
  }
  
  //スコア(統計情報)の更新成功
  private void OnUpdatePlayerStatisticsSuccess(UpdatePlayerStatisticsResult result){
    Debug.Log($"スコア(統計情報)の更新が成功しました");
  }

  //スコア(統計情報)の更新失敗
  private void OnUpdatePlayerStatisticsFailure(PlayFabError error){
    Debug.LogError($"スコア(統計情報)更新に失敗しました\n{error.GenerateErrorReport()}");
  }

}


実際に使ってみると以下のような感じで、

送信したスコアがブラウザ上で表示されているのが分かると思います。

f:id:kan_kikuchi:20200115104416g:plain



ランキング取得

ランキングの取得方法ですが、

他の処理と同様にログイン処理を先に行います。


そしてその後、GetLeaderboardRequestのインスタンスを生成し、

PlayFabClientAPI.GetLeaderboardにそれプラス、成功時と失敗時のデリゲートを渡すだけ。

using System.Collections.Generic;
using PlayFab;
using PlayFab.ClientModels;
using UnityEngine;
using UnityEngine.UI;

/// <summary>
/// ランキングのサンプル
/// </summary>
public class RankingSample : MonoBehaviour {

  [SerializeField]
  private Text _rankingText = default;

  //=================================================================================
  //ランキング取得
  //=================================================================================

  /// <summary>
  /// ランキング(リーダーボード)を取得
  /// </summary>
  public void GetLeaderboard() { 
    //GetLeaderboardRequestのインスタンスを生成
    var request = new GetLeaderboardRequest{
      StatisticName   = "ランキングサンプル", //ランキング名(統計情報名)
      StartPosition   = 0,                 //何位以降のランキングを取得するか
      MaxResultsCount = 3                  //ランキングデータを何件取得するか(最大100)
    };

    //ランキング(リーダーボード)を取得
    Debug.Log($"ランキング(リーダーボード)の取得開始");
    PlayFabClientAPI.GetLeaderboard(request, OnGetLeaderboardSuccess, OnGetLeaderboardFailure);
  }
  
  //ランキング(リーダーボード)の取得成功
  private void OnGetLeaderboardSuccess(GetLeaderboardResult result){
    Debug.Log($"ランキング(リーダーボード)の取得に成功しました");

    //result.Leaderboardに各順位の情報(PlayerLeaderboardEntry)が入っている
    _rankingText.text = "";
    foreach (var entry in result.Leaderboard) {
      _rankingText.text += $"\n順位 : {entry.Position}, スコア : {entry.StatValue}, 名前 : {entry.DisplayName}, ID : {entry.PlayFabId}";
    }
  }

  //ランキング(リーダーボード)の取得失敗
  private void OnGetLeaderboardFailure(PlayFabError error){
    Debug.LogError($"ランキング(リーダーボード)の取得に失敗しました\n{error.GenerateErrorReport()}");
  }

}


さきほどのスコア送信と併せて実際に使ってみると以下のような感じで、

指定した数だけ上位の順位が取得出来ている事が分かると思います。

f:id:kan_kikuchi:20200115114050g:plain


なお、PlayFabClientAPI.GetLeaderboardAroundPlayerを使うことで、

自分周辺の順位を取得する事も可能です。

using System.Collections.Generic;
using PlayFab;
using PlayFab.ClientModels;
using UnityEngine;
using UnityEngine.UI;

/// <summary>
/// ランキングのサンプル
/// </summary>
public class RankingSample : MonoBehaviour {

  [SerializeField]
  private Text _rankingText = default;

  //=================================================================================
  //ランキング取得
  //=================================================================================
  
  /// <summary>
  /// 自分の順位周辺のランキング(リーダーボード)を取得
  /// </summary>
  public void GetLeaderboardAroundPlayer() { 
    //GetLeaderboardAroundPlayerRequestのインスタンスを生成
    var request = new GetLeaderboardAroundPlayerRequest{
      StatisticName   = "ランキングサンプル", //ランキング名(統計情報名)
      MaxResultsCount = 3                  //自分を含め前後何件取得するか
    };

    //自分の順位周辺のランキング(リーダーボード)を取得
    Debug.Log($"自分の順位周辺のランキング(リーダーボード)の取得開始");
    PlayFabClientAPI.GetLeaderboardAroundPlayer(request, OnGetLeaderboardAroundPlayerSuccess, OnGetLeaderboardAroundPlayerFailure);
  }
  
  //自分の順位周辺のランキング(リーダーボード)の取得成功
  private void OnGetLeaderboardAroundPlayerSuccess(GetLeaderboardAroundPlayerResult result){
    Debug.Log($"自分の順位周辺のランキング(リーダーボード)の取得に成功しました");

    //result.Leaderboardに各順位の情報(PlayerLeaderboardEntry)が入っている
    _rankingText.text = "";
    foreach (var entry in result.Leaderboard) {
      _rankingText.text += $"\n順位 : {entry.Position}, スコア : {entry.StatValue}, 名前 : {entry.DisplayName}, ID : {entry.PlayFabId}";
    }
  }

  //自分の順位周辺のランキング(リーダーボード)の取得失敗
  private void OnGetLeaderboardAroundPlayerFailure(PlayFabError error){
    Debug.LogError($"自分の順位周辺のランキング(リーダーボード)の取得に失敗しました\n{error.GenerateErrorReport()}");
  }

}
f:id:kan_kikuchi:20200115114101g:plain



おわりに

タイトルデータユーザデータ同様に

やはりランキングもびっくりするほど簡単に実装が行えました。


これを使えばiOSとAndroidなど別のプラットフォームで共通のランキングが

簡単に作れるので、マルチプラットフォームにリリースする際にはかなり魅力的だと思います。


ちなみにランキングの順位に応じて報酬を配布するという事も可能なようなので、

これについてもそのうち試して、記事にしたいと思います。


参考