見出し画像

【Unity】Steamでオンラインランキング/リーダーボードを実装する【Steamworks】

Steamでオンラインランキングを実装してみたので忘備録として書いておきます。

オンラインランキングを実装する流れとしては
①Steamworks管理画面にランキングを作成
②Steamworks.NETをUnityにインストール
③UnityにてオンラインランキングをC#で実装
といった感じになります。

実装にあたり
Steamのランキング(リーダーボード)をUnityで実装する【Unity】【Steam】
Unity製ゲームで、Steamのランキング実装をするには
コチラのサイトさんを参考にさせて頂きました。

①Steamworks管理画面にランキングを作成

Steamworks管理画面のテクニカルツールにあるSteamworks設定編集→データ&実績→ランキングを選択します。
ランキングを追加で任意の名前を付けて作成します。

パラメータの内容はSteamworksの説明から抜粋

*********************************************************************
名前-ここには、内部開発用に意味のある名前を設定します。

コミュニティ名-ランキングをコミュニティハブに表示する場合は、ここに一般公開用の名前を設定します。 名前が入力されていない場合は、ランキングは表示されません。

並べ替え方法-ランキングの並べ替え順序を設定します。 順位が基準のランキングでは昇順を使用し、 ハイスコアが基準の場合は、降順を使用してください。

表示タイプ-ランキングで表示するデータのタイプを決定します。 数値、秒またはミリ秒から選択します。

書き込み-これが「信頼済み」に設定されている場合、クライアントによってランキングスコアを設定することはできず、SetLeaderboardScore WebAPIによってのみ設定できます。 デフォルトでは設定されていません。

読み取り-これが「フレンド」に設定されている場合、ゲームはユーザーのフレンドのランキングスコアのみを読み取ることができます。すべてのスコアはWebAPIによって常に読み取り可能です。 デフォルトでは設定されていません。
*********************************************************************

書き込みと読み込みは特別な事をしない限りは設定する必要なさそうです。
並べ替え方法1位から順番に表示したい場合は降順にします。

実施したいランキングの数だけ作成します。
(例えばイージーとノーマルとハードに分けたかったら3個作る)
ランキングを作成したらココでの設定は終了です。

②Steamworks.NETをUnityにインストール
アセットストアにもあるみたいですが公式の?Githubからダウンロードするのが良さげ
Releases · rlabrecque/Steamworks.NET
ちょっと下にあるSteamworks.NET_20.1.0.unitypackageをダウンロードしてAssets→Import Package→Custom Packageでインストールします。

インストールしたらゲームプロジェクトフォルダの一番上の階層にsteam_appid.txtがあると思うので、それを開くのですがUnityからは見えないのでWindowsからテキストエディタで開きます。
初期は480?かと思いますので、自分のゲームのID(Steamworksに表示されているゲームタイトルの横にある数字)を入力して保存します。
保存したらココでの設定は終了です。

③UnityにてオンラインランキングをC#で実装
※オンラインランキングを使用するときはUnityと同時にSteamも立ち上げておかないとエラーが出るので注意が必要です。

ランキングを使用するスクリプトには一番初めに
using Steamworks;
を記述する必要があります。

ランキング送受信する時のC#スクリプトはこんな感じ。

リーダーボードの取得

//===========================================================
//リーダーボードの取得
//===================================================================
    if (SteamManager.Initialized)
    {
   Debug.Log($"Steamの初期化成功, AppID : {SteamUtils.GetAppID()}");

    //初期化が成功したらリーダーボードを探す(OnFindLeaderboardを実行する)
    CallResult<LeaderboardFindResult_t>.Create().Set(SteamUserStats.FindLeaderboard("作成したランキング名"), OnFindLeaderboard);

    }
        else
    {
        Debug.LogWarning("Steamの初期化失敗 / Failure Initialization");
    }


    private void OnFindLeaderboard(LeaderboardFindResult_t result, bool failure)
    {
        //リーダーボードが見つかったか判定
        if (failure || result.m_bLeaderboardFound == 0)
        {
            Debug.LogWarning("リーダーボードが見つかりませんでした  / Failure LeaderBoard");
            return;
        }
        //リーダーボードの情報表示
        var leaderboard = result.m_hSteamLeaderboard;
        
        Debug.Log($"リーダーボードの名前 : {SteamUserStats.GetLeaderboardName(leaderboard)}");
        Debug.Log($"リーダーボードに登録されている数 : {SteamUserStats.GetLeaderboardEntryCount(leaderboard)}");
        Debug.Log($"リーダーボードの並べ替え方法 : {SteamUserStats.GetLeaderboardSortMethod(leaderboard)}");
        Debug.Log($"リーダーボードの表示タイプ : {SteamUserStats.GetLeaderboardDisplayType(leaderboard)}");
    }


ランキングの取得

//順位の取得
CallResult<LeaderboardFindResult_t>.Create().Set(SteamUserStats.FindLeaderboard("作成したランキング名"), DownloadEntries);

//==========================================================
//順位の取得
//===========================================================

    //順位の取得
    private void DownloadEntries(LeaderboardFindResult_t result, bool failure)
    {
        //リーダーボードが見つかったか判定
        if (failure || result.m_bLeaderboardFound == 0)
        {
            Debug.LogWarning("リーダーボードが見つかりませんでした  / Failure LeaderBoard");
            return;
        }

        //取得する情報
        CSteamID[] targetIDs = { SteamUser.GetSteamID() };//取得したい情報のIDに、自分のIDを設定
        var call = SteamUserStats.DownloadLeaderboardEntriesForUsers(
          result.m_hSteamLeaderboard, //送信するリーダーボード 
          targetIDs,       //取得したいUserのID
          targetIDs.Length //取得したい情報の個数
        );

        //順位の取得送信
        //Debug.Log("順位の取得開始");
        CallResult<LeaderboardScoresDownloaded_t>.Create().Set(call, OnDownloadEntriese2);

        //取得する情報
        call = SteamUserStats.DownloadLeaderboardEntries(
          result.m_hSteamLeaderboard, //送信するリーダーボード 
          ELeaderboardDataRequest.k_ELeaderboardDataRequestGlobal, //順位を取得する範囲
          ranking_tate, //取得する順位の一番上
          ranking_tate + 9 //取得する順位の一番下
        );
        
        //順位の取得送信
        Debug.Log("順位の取得開始");
        CallResult<LeaderboardScoresDownloaded_t>.Create().Set(call, OnDownloadEntriese);


        
    }

    //順位の取得完了
    private void OnDownloadEntriese(LeaderboardScoresDownloaded_t result, bool failure)
    {
        //順位の取得が上手くいったか判定
        if (failure)
        {
            Debug.LogWarning("順位の取得が失敗しました / Failure");
            return;
        }
        Debug.Log($"順位の取得完了");


        //登録されている順位の個数を確認
        Debug.Log($"取得した順位の個数 : {result.m_cEntryCount}");

        //各順位の情報を確認
        for (int i = 0; i < result.m_cEntryCount; i++)
        {
            //各順位の情報を取得
            LeaderboardEntry_t leaderboardEntry;
            SteamUserStats.GetDownloadedLeaderboardEntry(result.m_hSteamLeaderboardEntries, i, out leaderboardEntry, new int[0], 0);

            //情報を表示
            /*
            Debug.Log($"順位 : {leaderboardEntry.m_nGlobalRank}");
            Debug.Log($"ID : {leaderboardEntry.m_steamIDUser}");
            Debug.Log($"スコア : {leaderboardEntry.m_nScore}");
            Debug.Log($"ユーザ名 : {SteamFriends.GetFriendPersonaName(leaderboardEntry.m_steamIDUser)}");
            */
        }
    }


スコアの送信

//スコアの送信
    if (SteamManager.Initialized)//初期化して成功したらリーダーボードを探してスコアアップロード
    {
        Debug.Log($"Steamの初期化成功, AppID : {SteamUtils.GetAppID()}");
        //初期化が成功したらリーダーボードを探す
        CallResult<LeaderboardFindResult_t>.Create().Set(SteamUserStats.FindLeaderboard("作成したランキング名"), UploadScore);
    }
    else
    {
        Debug.LogWarning("Steamの初期化失敗");
    }

//=================================================
//スコアの送信
//=================================================

    //スコア送信
    private void UploadScore(LeaderboardFindResult_t result, bool failure)
    {
        //リーダーボードが見つかったか判定
        if (failure || result.m_bLeaderboardFound == 0)
        {
            Debug.LogWarning("リーダーボードが見つかりませんでした");
            return;
        }

        //送信する情報
        var call = SteamUserStats.UploadLeaderboardScore(
          result.m_hSteamLeaderboard, //送信するリーダーボード 
          ELeaderboardUploadScoreMethod.k_ELeaderboardUploadScoreMethodKeepBest,//送信するスコアがベストを超えていれば更新する
          0000000000, //送信するスコアを記入する
          new int[0], //ユーザがスコアを獲得した方法に関する追加情報?
          0       //ユーザがスコアを獲得した方法に関する追加情報?
        );

        //スコア送信
        Debug.Log($"スコア送信開始");
        CallResult<LeaderboardScoreUploaded_t>.Create().Set(call, OnUploadScore);
    }

    //スコア送信完了
    private void OnUploadScore(LeaderboardScoreUploaded_t result, bool failure)
    {
        //スコア送信が上手くいったか判定
        if (failure || result.m_bSuccess != 1)
        {
            Debug.LogWarning("スコア送信が失敗しました");
            return;
        }
        Debug.Log($"スコア送信完了");

        //更新結果を確認
        Debug.Log($"現在のスコア : {result.m_nScore}");
        Debug.Log($"スコアが更新されたか : {result.m_bScoreChanged}");
        Debug.Log($"スコア送信前の順位 : {result.m_nGlobalRankPrevious}");
        Debug.Log($"スコア送信後の順位 : {result.m_nGlobalRankNew}");
    }

流れとしてはリーダーボードを取得してランキング取得して表示もしくは送信を行うだけなので、ランキングの取得とスコアの送信が出来れば何とかなる感じです。
取得した順位はテキストなどに入れて表示すればランキング表が出来ます。

ただ、あまり頻繁に取得すると表示制限?が掛かるみたいで取得出来なくなるので、あまり更新頻度は上げない方が良さそうです。

いいなと思ったら応援しよう!