Unityゲームにスコアボードとリーダーボードを追加する方法
Published: 2024-05-15 02:57:53

スコアボードとリーダーボードは、プレイヤーのエンゲージメントを促進する上で重要な要素です。スコアボードは、プレーヤーが激しい試合をしている間に重要な情報を提供し、勝利の可能性を判断するために必要です。一方、リーダーボードは、試合後にハイスコアを見るためにプレーヤー間の競争を促す方法として使用されます。どちらもリプレイ性を促し、プレイヤーを定着させる簡単な方法です。

スコアボードとリーダーボードは、健全な競争を促進し、ゲーム中に重要なフィードバックを提供するためにゲーム開発に不可欠ですが、あなたのUnityプロジェクトにこれらの機能を組み込むことは言うほど簡単ではありません。ゼロから始めるには、スコアボードの更新を通信したり、更新されたリーダーボードのスコアを保存したりする必要があるため、構築、維持、プレイヤーの増加に伴う拡張には多くのリソースが必要です。幸いにも、PubNubは私たちのリアルタイム、低遅延APIプラットフォームでUnityゲームにリアルタイム機能を注入することがこれまで以上に簡単になりました。私たちはあなたのアプリケーションのインフラストラクチャ層を引き受けますので、あなたはアプリケーションに集中することができます。Windows、Mac、iOS、Android、OculusやMeta Questのようなバーチャルリアリティシステム、またはクロスプラットフォーム向けに開発しているかどうかにかかわらず、私たちの[Unity SDKは](https://www.pubnub.com/docs/sdks/unity?utm_source=medium&utm_medium=syndication&utm_campaign=off_domain&utm_content=ja)あなたをカバーしています。

このガイドに従う際の参考として、Unityゲームにスコアボードとリーダーボードを実装する方法の例をご覧になりたい場合は、[Unity Showcase Gameを](https://github.com/PubNubDevelopers/unity-multiplayer-shooter)ぜひご覧ください。

PubNub GameObjectの設定方法から始まり、PubNub Functionsについて学び、ゲームのニーズに合わせてPubNubメッセージを解析する方法まで、リアルタイムで更新されるスコアボードとリーダーボードをUnityゲームに追加する方法を順を追って学びます。

PubNubを始める
----------

あなたのUnityゲームにスコアボードとリーダーボードを設定する方法を理解し始める前に、PubNubを理解し、プラットフォームの機能を利用するためにアプリケーションを構成する方法を理解する必要があります。

### 概要

PubNubはPub/Sub（Publish/Subscribe）モデルに基づいています。ユーザーは、基本的にすべての関連情報を含むペイロードであるメッセージをPubNubネットワークに[公開](https://www.pubnub.com/docs/general/messages/publish?utm_source=medium&utm_medium=syndication&utm_campaign=off_domain&utm_content=ja)します。メッセージと他の生成されたイベントを受信またはリスニングしたいユーザーは、PubNubネットワークに[サブスクライブ](https://www.pubnub.com/docs/general/messages/receive?utm_source=medium&utm_medium=syndication&utm_campaign=off_domain&utm_content=ja)し、メッセージを解析します。[イベントリスナーは](https://www.pubnub.com/docs/general/messages/receive#add-a-listener?utm_source=medium&utm_medium=syndication&utm_campaign=off_domain&utm_content=ja)、PubNubネットワークで生成されたメッセージやイベントをキャッチし、行われたアクションに基づいてトリガするために使用されます。

メッセージが適切な受信者に確実に届くようにするために、あるデバイスから別のデバイスにデータが送信されるメカニズムとして[チャネルが](https://www.pubnub.com/docs/general/channels/overview?utm_source=medium&utm_medium=syndication&utm_campaign=off_domain&utm_content=ja)使用されます。チャネルは、デバイスがPubNubネットワークにパブリッシュおよびサブスクライブするたびに必要になります。ユーザーは一度に1つのメッセージしか発行できませんが、ユーザーは一度に多くの異なるチャネルを購読できます。

### PubNub Unity SDKのインストールと設定

開始するには、任意のPubNub依存関係をインストールし、PubNub Unity SDKを設定してアプリケーションをPubNubネットワークに接続する必要があります。このガイドでは、すでにUnityゲームエンジン、Unityアセット、およびVisual Studioなどのコードエディタがインストールされていることを前提としています。詳細については[Unity SDKのドキュメントを](https://www.pubnub.com/docs/sdks/unity?utm_source=medium&utm_medium=syndication&utm_campaign=off_domain&utm_content=ja)参照してください：

1.  [パッケージマネージャから](https://www.pubnub.com/docs/sdks/unity#install-via-package-manager?utm_source=medium&utm_medium=syndication&utm_campaign=off_domain&utm_content=ja)Unityパッケージを追加します。
2.  [無料のPubNubアカウントを](https://admin.pubnub.com/?utm_source=medium&utm_medium=syndication&utm_campaign=off_domain&utm_content=ja)作成し、PubNubキーを取得します。アプリケーションが必要とするキーセットの機能を有効にする必要があります。このガイドでは、デフォルトの設定でStream Controllerを有効にする必要があります。もう1つの重要な機能であるFunctionsは、Functionを初期化すると自動的に有効になります。この機能についてはこのガイドで後述します。
3.  新しいUnityプロジェクトを作成するか、既存のゲームを開き、UnityエディタでPubNub GameObjectを[設定](https://www.pubnub.com/docs/sdks/unity#configure-pubnub?utm_source=medium&utm_medium=syndication&utm_campaign=off_domain&utm_content=ja)するために、前のステップで取得したpublishキーとsubscribeキーをUnityに提供します。すべてのPubNubオブジェクトはPubNubへの接続を確立するために一意の識別子を必要とするため、UserIdも提供する必要があります。そうしたら、PubNubオブジェクトを初期化します：

```js
using PubnubApi;
using PubnubApi.Unity;
…
PubNub pubnub = new Pubnub(pnConfiguration);
```

4.  あなたのゲームがメッセージに反応するための[イベントリスナーを](https://www.pubnub.com/docs/sdks/unity#add-event-listeners?utm_source=medium&utm_medium=syndication&utm_campaign=off_domain&utm_content=ja)追加します。ここで、あなたのバックエンドは基本的に新しいメッセージを受信したときの通知を受け取ります。各タイプのメッセージやイベントに応答するカスタムロジックを実装できるように、さまざまなイベントリスナーがありますが、このガイドでは単にメッセージイベントリスナーが必要です：

```js
var listener = new SubscribeCallbackListener();
pubnub.AddListener(listener);
listener.onMessage += OnPnMessage;
…
private void OnPnMessage(Pubnub pn, PNMessageResult<object> result) {
  Debug.Log($"Message received: {result.Message}");
  //Handle the message based on channel name, User ID, etc.
}
```

試合中の重要な情報スコアボード
---------------

スコアボードや得点システムは、試合中にプレイヤーにフィードバックを提供する方法としてゲームで使用されます。スコアボードは、価値のある、魅力的な、やりがいのあるフィードバックを提供し、楽しい体験とリプレイ性を促し、スコアを向上させるために不可欠です。Unityプロジェクトに実装できるさまざまなタイプのスコアボードについては、[スコアボードシステムガイドを](https://www.pubnub.com/how-to/develop-game-scoring-system/?utm_source=medium&utm_medium=syndication&utm_campaign=off_domain&utm_content=ja)ご覧ください。

試合中にスコアボードを更新するには、基本的にチャットメッセージを送信するのと同じですが、はるかに高速です：必要な情報で構成されるペイロードを構築し、すべてのサブスクライバが受信し、解析し、新しい情報が発生するたびにスコアボードを更新できるように、このメッセージを公開します。もしPubNubを使ってマルチプレイヤーシンクロナイゼーションなどの他のマルチプレイヤーフィーチャーを動かしているのであれば、送信するメッセージの数が膨大になり、トランザクションの数を減らすことができるので、この情報をバンドルすることをお勧めします。しかし、このガイドでは単にメッセージの送受信に必要なPubNubの機能に焦点を当てます。

スコアボードの実装を開始するには、試合中の人だけが更新を受信できるようにチャネルパターンを設定します。マルチプレイヤーシンクロナイゼーションのアーキテクチャにもよりますが、プレイヤーとの現在のマッチを一意に識別するルームIDやマッチIDが必要です。チャンネルを構築する際には、このIDを使用します：

```js
public string scoreboardUpdates = $“scoreboard.” + {RoomID};
```

チャンネルは文字列補間を使ってスコアボードチャンネルと現在のマッチの識別子を組み合わせます。このチャンネルに登録すると、チャンネルの更新をリッスンできるようになります：

```js
pubnub.Subscribe<string>()
  .Channels(new string[] {
    // subscribe to channels
    scoreboardUpdates
   })
  .Execute();
```

キルしたときやダメージスコアが上がったときなど、送信する更新があったら、メッセージを作成して更新を公開しましょう（スコアボードの更新だけでなく、より多くの情報を送信したい場合にも使えます）：

```js
Dictionary<string, object> leaderboardUpdates= new Dictionary<string, object>();
leaderboardUpdates.Add("userId", user-a-uuid);
leaderboardUpdates.Add("kills", 0);
leaderboardUpdates.Add("deaths", 0);
leaderboardUpdates.Add("assists", 0);
leaderboardUpdates.Add("total_damage", 0);
…
private async void PublishMessage(string text, string channel)
{
  await PNManager.pubnubInstance.pubnub.Publish()
    .Channel(scoreboardUpdates)
    .Message(text)
    .ExecuteAsync();
}
```

他のプレイヤーは、先ほど構築したMessage Event Listenerを介して新しいアップデートを受信します。そして、そのメッセージを解析し、それに応じてUIを更新する。これはゲームが終了するまで続き、その場合、あなたはグローバルリーダーボードを更新するために最後の呼び出しを行います。

ハイスコアランキングリーダーボード
-----------------

リーダーボードは、プレイヤー間の競争を高めるためにゲームに欠かせないもので、試合終了後やホーム画面の別メニューに表示されます。プレイヤーは、他のプレイヤーやギルド、クランと比較して自分の成績を確認し、より高いスコアを達成するために自分のプレイスタイルをどのように改善すればよいかを確認したいものです。Unityゲームに実装できるリーダーボードの種類について詳しく知りたい方は、[リーダーボードガイドを](https://www.pubnub.com/how-to/make-your-own-leaderboard/?utm_source=medium&utm_medium=syndication&utm_campaign=off_domain&utm_content=ja)ご覧ください。

オンラインリーダーボードの実装を始める前に、試合が終了したらリーダーボードを更新するだけでなく、サーバーを立ち上げることなくリーダーボードの情報を保存する方法について説明する必要があります。

[Functionsを](https://www.pubnub.com/products/functions/?utm_source=medium&utm_medium=syndication&utm_campaign=off_domain&utm_content=ja)使用すると、開発者はエッジ上でビジネスロジックを作成して実行し、PubNubネットワークを経由するリアルタイムのメッセージをルーティング、フィルタリング、変換、増強、集約することができます。サーバーを立ち上げることなく、このビジネスロジックをホストすることができ、信頼できる[サードパーティの統合機能](https://www.pubnub.com/integrations/?utm_source=medium&utm_medium=syndication&utm_campaign=off_domain&utm_content=ja)（Functionsで動作するようにすでに設定されており、開始するための手順が含まれています）と統合したり、プレイヤーに送信する前または後にカスタムロジックを実行するコードを記述したりすることができます。[KVストアモジュールを使って](https://www.pubnub.com/docs/sdks/functions/kvstore-module?utm_source=medium&utm_medium=syndication&utm_campaign=off_domain&utm_content=ja)関連情報を保存することもできます。これは、Functionsのデータベースとして機能する永続的なキーバリューストアです。Functionsの詳細については、[ドキュメントを](https://www.pubnub.com/docs/general/serverless/functions/overview?utm_source=medium&utm_medium=syndication&utm_campaign=off_domain&utm_content=ja)ご覧ください。

リーダーボードでは、プレイヤーが試合を終えた後にスコアを更新し、更新されたリーダーボードをプレイヤーに通知します。

Functionsを使用できるようにするには、管理者ポータルでさらにいくつかの設定を行う必要があります：

1.  [管理者](https://admin.pubnub.com/?utm_source=medium&utm_medium=syndication&utm_campaign=off_domain&utm_content=ja)ポータルに移動します。
2.  ポータルの左側にあるFunctionsタブをクリックします。
3.  前のセクションで作成したアプリとキーセットを選択します。
4.  Create New Moduleをクリックします。
5.  モジュールに名前を付けます。
6.  モジュールの説明を入力します。
7.  モジュールを追加するために、先ほど作成したキーセットを選択します。Create をクリックします。
8.  Functionに名前を付けます。
9.  After Publish または Fire イベントタイプを選択します。
10.  メッセージが公開された後に関数が更新するチャネル名を入力します (これも後で調整できます)。[Subscribeの](https://www.pubnub.com/docs/general/channels/subscribe#wildcard-subscribe?utm_source=medium&utm_medium=syndication&utm_campaign=off_domain&utm_content=ja)ワイルドカード文字\*で構成される、score.\*のようなチャネル名を使用します。チャットメッセージの Wildcard Subscribe の動作については、以下の[ガイドを](https://www.pubnub.com/how-to/add-real-time-chat-to-your-unity-game/#h-3?utm_source=medium&utm_medium=syndication&utm_campaign=off_domain&utm_content=ja)参照してください。
11.  各機能の作成ボタンをクリックします。

Functionの概要ページが表示され、設定を変更したり、テストしたり、各Functionのゲームとのインタラクションを監視したりすることができます。 画面の中央には、自動的に生成されたJavaScriptコードが表示されているはずです。これは "Hello World "ファンクションのサンプルで、ファンクションがどのように動作するか、また、あなたのコードをホストしたり、サードパーティ統合のビジネスロジックを実行することができます。

リーダーボードについては、いくつかのカスタムロジックを記述し、KVストアモジュールを使用してリーダーボード情報を保存します。コードセクションでは、リーダーボード情報の内容を検討する必要があります。複数のリーダーボードで異なる情報を表示するのか、複数の統計情報を含む大きなリーダーボードで、ゲーム内で異なるリーダーボードを作成できるようにするのか。

保存したい情報が決まったら、ゲーム内でPubNubネットワークにパブリッシュされ、ファンクションでキャッチされるメッセージペイロードを設定する必要があります。

例えば、私たちの[Unity Showcase Gameでは](https://github.com/PubNubDevelopers/unity-multiplayer-shooter)、試合中の各プレイヤーの名前とスコア（キル/デス/アシストの組み合わせ）を送信します。メッセージはJSONでフォーマットされ、Functionがリッスンしているチャンネル score.leaderboard に[公開さ](https://www.pubnub.com/docs/sdks/unity/api-reference/publish-and-subscribe#publish?utm_source=medium&utm_medium=syndication&utm_campaign=off_domain&utm_content=ja)れます（Wildcard Subscribeに基づく）。[UIManager.csファイル](https://github.com/PubNubDevelopers/unity-multiplayer-shooter/blob/b3f8f97fab50dc3f94a0283badf03e706566cc5f/Assets/SuperMultiplayerShooter/Scripts/UIManager.cs#L143)を見てください：

```js
…
 // Get the kills and deaths value of all players and store them in an INT array:
 int[] kills = new int[playersSorted.Length];
 int[] deaths = new int[playersSorted.Length];
 int[] otherScore = new int[playersSorted.Length];
 for (int i = 0; i < playersSorted.Length; i++)
 {
   kills[i] = playersSorted[i].Kills;
   deaths[i] = playersSorted[i].Deaths;
   otherScore[i] = playersSorted[i].OtherScore;
   if (notPublished)
   {
     if (playersSorted[i].PlayerName == Connector.PNNickName)
     {
       MyClass mc = new MyClass();
       mc.username = Connector.PNNickName;
       mc.score = playersSorted[i].Kills.ToString();
       string json = JsonUtility.ToJson(mc);
       PublishMessage(json, _leaderboardChannelPub);
      }
      notPublished = false;
    }
  }
…

private async void PublishMessage(string text, string channel)
{
  await PNManager.pubnubInstance.pubnub.Publish()
    .Channel(channel)
    .Message(text)
    .ExecuteAsync();
}
```

このチャンネルでリッスンしている関数がトリガーされ、ソート、KVストアモジュールの新しいスコアの更新、新しいリーダーボードの更新をプレイヤーに知らせることができます。Unity Showcase Gameの場合、関数内の以下のロジックがまさにこれを行います：

```js
//This function takes a string from a unity game that contains either a username AND and a score, OR a refresh message.
//The function then looks at the message and creates a user/score json and sends it back. Putting the highest score in 0 and the lowest score in [9]
//If the score submitted is lower than [9] then trhe messages succeeds without intervention
//sending a refresh will trigger this function without any intervention.

export default (request) => {
  const db = require("kvstore");
  const pubnub = require("pubnub");
 //uncomment if you want to see the raw message
 //console.log(request.message);
 //The format of the message sent is "{\"username\":\"Bob\",\"score\":\"10\",\"refresh\":\"\"}"  and as such we need to parse it 
  //You wont be able to use the test payload until you remove the parse
  // var json = request.message; //uncomment this and comment the line below to be able to use the test payload (as well as debug console)
  var json = JSON.parse(request.message);
  let { username, score } = json;

  //create some arrays to ultimately be able to position the leaderboard correctly - there's more elegant ways to do this, this function is designed to explain
  var scorearrayprevious = [];
  var scorearraynew = [];
  var usernamearraynew = [];
  var usernamearrayprevious = [];

  //db.removeItem("data"); //uncomment this code if you need to wipe the database -- for future you could always send a message to trigger this, but that is out of the scope for this workshop
  db.get("data").then((value) => {
  if(value){
    console.log("value", value); //uncomment this if you want to see the value 
    let i = 0;
    //we use some and score > item to parse through where the submitted score will sit, if the score is greater than the item we're on, then it get's slotted in to the array at that spot
    value.score.some(item => {
        if(parseFloat(score) > parseFloat(item) || (parseFloat(item) == 0 && score.length > 0)){ //Parse into float since variables are currently strings
          //Score
          scorearraynew = value.score.slice(0, i);
          scorearrayprevious = value.score.slice(i, value.score.length);
          console.log("values", scorearraynew, scorearrayprevious);
          scorearraynew.push(score);
          var newScoreList = scorearraynew.concat(scorearrayprevious);
          newScoreList.splice(-1,1);

          //Username
          usernamearrayprevious = value.username.slice(0, i);
          usernamearraynew = value.username.slice(i, value.score.length);
          console.log("values", usernamearrayprevious, usernamearraynew);
          usernamearrayprevious.push(username);
          var newUsername = usernamearrayprevious.concat(usernamearraynew);
          newUsername.splice(-1,1);

          value.score = newScoreList;
          value.username = newUsername;
          //store the 
          db.set("data", value);

          return true; //break out of the loop using Array.prototype.some by returning true
       }
        i++;
    });
    //publish the message to a *new* or *different* channel 
    pubnub.publish({
        "channel": "leaderboard_scores",
        "message": value
    }).then((publishResponse) => {
        console.log("publish response", publishResponse);
    });
} else {
  //Initial Data, used only on the first call
    db.set("data", {
        "username":["---","---","---","---","---","---","---","---","---","---"], 
        "score":["0","0","0","0","0","0","0","0","0","0"]});
}
    }); 
    return request.ok();
};    
```

そして、リーダーボードの更新を、leaderboard\_scores チャンネルを通じて、すべてのプレイヤーに公開します。アプリケーションに戻って、[Subscribe](https://www.pubnub.com/docs/sdks/unity/api-reference/publish-and-subscribe#subscribe?utm_source=medium&utm_medium=syndication&utm_campaign=off_domain&utm_content=ja)コールでこのチャンネルを購読する必要があります：

```js
pubnub.Subscribe<string>()
  .Channels(new string[] {
    // subscribe to channels
    "leaderboard_scores”
  })
  .Execute();
```

あなたは`leaderboard_scores`チャンネルを購読しているので、関数が終了すると、メッセージイベントリスナーを通して、更新されたリーダーボードのスコアを受け取ることができます。メッセージを解析して、それに応じてリーダーボードのUIを更新することができます。例えば、Unity Showcase Game UIのリーダーボードを更新する場合です：

```js
private void OnPnMessage(PNMessageResult<object> result)
{
  // Enable the button once we have established connection to PubNub 
  if (result.Channel.Equals(PubNubUtilities.chanLeaderboardSub))
  {
    Dictionary<string, object> msg = JsonConvert.DeserializeObject<Dictionary<string, object>>(result.Message.ToString());// as Dictionary<string, object>;
    var usernames = (msg["username"] as Newtonsoft.Json.Linq.JArray).ToObject<string[]>();
    var scores = (msg["score"] as Newtonsoft.Json.Linq.JArray).ToObject<string[]>();

    if (usernames[0] != null)
    {
        namePos1.text = usernames[0];
        kdPos1.text = scores[0];
    }

    if (usernames[1] != null)
    {
        namePos2.text = usernames[1];
        kdPos2.text = scores[1];
    }

    if (usernames[2] != null)
    {
        namePos3.text = usernames[2];
        kdPos3.text = scores[2];
    }

    if (usernames[3] != null)
    {
        namePos4.text = usernames[3];
        kdPos4.text = scores[3];
    }

    if (usernames[4] != null)
    {
        namePos5.text = usernames[4];
        kdPos5.text = scores[4];
    }
  }
}
```

Unity Showcase Gameのリーダーボードの実装については、[Leaderboard.csを](https://github.com/PubNubDevelopers/unity-multiplayer-shooter/blob/main/Assets/SuperMultiplayerShooter/Scripts/Leaderboard.cs)参照してください。

次へ
--

このハウツーガイドでは、Unityゲームにリーダーボードとスコアボードを追加する方法を学びました。スコアボードを追加するには、PubNubの低レイテンシプラットフォームを使用して、キル、デス、アシストなどの試合中に関連する情報を含むメッセージを送受信し、プレイヤーをリアルタイムで更新することができます。リーダーボードでは、プレイヤースコアを更新するコードをホストし、マッチが終了した後にプレイヤーが閲覧できるようにリーダーボードを更新することができます。

ゲーム開発者の方は、以下のリソースをご参照ください：

-   [ドキュメントを](https://www.pubnub.com/docs/sdks/unity?utm_source=medium&utm_medium=syndication&utm_campaign=off_domain&utm_content=ja)読む。
-   [Unityでリアルタイムチャットを追加する方法を](https://www.pubnub.com/how-to/add-real-time-chat-to-your-unity-game/?utm_source=medium&utm_medium=syndication&utm_campaign=off_domain&utm_content=ja)ご覧ください。
-   [Unityショーケース](https://github.com/PubNubDevelopers/unity-multiplayer-shooter)ゲームでスコアボードとリーダーボードをリアルタイムで実装する方法を理解する。
-   [Unity SDKのソース](https://github.com/pubnub/unity)コードをご覧ください。

ご質問やご不明な点がございましたら、[devrel@pubnub.com](mailto:devrel@pubnub.com)のデベロッパーリレーションズチームまでお気軽にお問い合わせください。

PubNubはどのようにあなたを助けることができますか？
============================

この記事は[PubNub.comに](https://www.pubnub.com/how-to/add-scoreboard-and-leaderboard-to-your-unity-game/?utm_source=medium&utm_medium=syndication&utm_campaign=off_domain&utm_content=ja)掲載されたものです。

PubNubのプラットフォームは、開発者がWebアプリ、モバイルアプリ、IoTデバイス向けにリアルタイムのインタラクティブ機能を構築、提供、管理できるように支援します。

私たちのプラットフォームの基盤は、業界最大かつ最もスケーラブルなリアルタイムエッジメッセージングネットワークです。世界15か所以上で8億人の月間アクティブユーザーをサポートし、99.999%の信頼性を誇るため、停電や同時実行数の制限、トラフィックの急増による遅延の問題を心配する必要はありません。

PubNubを体験
---------

[ライブツアーを](https://www.pubnub.com/tour/introduction/?utm_source=medium&utm_medium=syndication&utm_campaign=off_domain&utm_content=ja)チェックして、5分以内にすべてのPubNub搭載アプリの背後にある本質的な概念を理解する

セットアップ
------

[PubNubアカウントに](https://admin.pubnub.com/signup/?utm_source=medium&utm_medium=syndication&utm_campaign=off_domain&utm_content=ja)サインアップすると、PubNubキーに無料ですぐにアクセスできます。

始める
---

[PubNubのドキュメントは](https://www.pubnub.com/docs?utm_source=medium&utm_medium=syndication&utm_campaign=off_domain&utm_content=ja)、ユースケースや[SDKに](https://www.pubnub.com/docs?utm_source=medium&utm_medium=syndication&utm_campaign=off_domain&utm_content=ja)関係なく、あなたを立ち上げ、実行することができます。