やったこと
unity-simple-ranking を改造して、ランキングデータベースに各プレイヤーのキャラクターアイコンを登録できるようにしました。
更に、それをランキング画面に表示できるようにしました。
(Unity1Week の参加作品 にて、これを実装してみました。)
※ unity-simple-ranking の中身を編集しているので気を付けてください。
環境
・Unity 2021.3.8f1
・unity-simple-ranking v2.2
・NCMB v4.5.0
準備
https://blog.naichilab.com/entry/webgl-simple-ranking を参考に、NCMB と unity-simple-ranking をプロジェクトにインポートしてください
方針
「ランキング画面呼び出し時」、「データベース登録時」、「ランキング表示時」にそれぞれ処理を加えます。
ランキング画面呼び出し時
unity-simple-ranking では、ランキング画面呼び出し時に、自分のスコアを引数で渡しています。 (RankingLoader.Instance.SendScoreAndShowRanking()
で呼んでいます。)
ここに、キャラクターアイコンID
も引数で渡すようにします。
データベース登録時
unity-simple-ranking では、RankingSceneManager.cs
内の SendScoreEnumerator()
でレコード登録処理をしています。
「名前」と「スコア」の2つのデータを含んだレコードを、データベースに登録しています。
ランキング表示時、この2つのデータからでは「キャラクターアイコン」の情報を得ることが出来ません。
従って、ランキング登録時に キャラクターアイコンID
と 名前
と スコア
の3つのデータを含んだレコードを、データベースに登録する必要があります。
キャラクターアイコンは、アイコン画像そのものを登録するのではなく、「どのキャラクターアイコンか」を判別するための ID を登録します。ここでは整数値で登録します。
↑ の対応により、ランキング画面呼び出し時の引数に キャラクターアイコンID
を追加したので、それを登録します。
ランキング表示時
↑ の対応により、各レコードには キャラクターアイコンID
のデータが含まれているので、表示側では ID に対応する画像を表示します。
ランキング表示時の各ノードは naichilab\unity-simple-ranking\Prefabs\RankingNode.prefab
を使用しています。
このプレハブには、キャラクターアイコンを表示する場所が用意されていません。従って、キャラクターアイコン表示用のオブジェクト、コンポーネントを追加しておく必要がります。
(それと、当然ですがキャラクターアイコン画像を用意しておきましょう。)
実装
スクリプト
ランキング画面呼び出し
・RankingLorder.cs
に、フィールドを追加します。
[NonSerialized] public int LastIcon = 0; // ランキング呼び出し側で指定したキャラクターアイコンを一時保存する場所
・RankingLorder.cs
に、「キャラクターアイコンID を引数に入れられるランキング画面呼び出し関数」を追加します。
public void SendScoreAndShowRankingWithIcon(TimeSpan time, int icon = 0, int boardId = 0)
{
var board = RankingBoards.GetRankingInfo(boardId);
var sc = new TimeScore(time, board.CustomFormat);
SendScoreAndShowRankingWithIcon(sc, icon, board);
}
public void SendScoreAndShowRankingWithIcon(double score, int icon = 0, int boardId = 0)
{
var board = RankingBoards.GetRankingInfo(boardId);
var sc = new NumberScore(score, board.CustomFormat);
SendScoreAndShowRankingWithIcon(sc, icon, board);
}
private void SendScoreAndShowRankingWithIcon(IScore score, int icon = 0, RankingInfo board)
{
if (board.Type != score.Type)
{
throw new ArgumentException("スコアの型が違います。");
}
CurrentRanking = board;
LastScore = score;
LastIcon = icon; // ここで引数のキャラクターアイコンIDを保存。ランキングシーンで参照されます
SceneManager.LoadScene("Ranking", LoadSceneMode.Additive);
}
データベース登録
・RankingSceneManager.cs
に以下の定数、フィールド、シリアライズフィールドを追加します。
private const string COLUMN_ICON = "icon"; // レコード内の項目名
private int _lastIcon; // 自分のキャラクターアイコンID。自分のランキングを送信するときに使用
[SerializeField] private Sprite[] icons; // キャラクターアイコン画像の配列。ここに入っている画像を表示します
RankingSceneManager.cs
の Start()
にて、 RankingLoader.cs
の LastIcon
フィールド値を読み込みます。
void Start()
{
sendScoreButton.interactable = false;
_board = RankingLoader.Instance.CurrentRanking;
_lastScore = RankingLoader.Instance.LastScore;
_lastIcon = RankingLoader.Instance.LastIcon; // ← ここ追加
Debug.Log(BoardIdPlayerPrefsKey + "=" + PlayerPrefs.GetString(BoardIdPlayerPrefsKey, null));
StartCoroutine(GetHighScoreAndRankingBoard());
}
・RankingSceneManager.cs
の SendScoreEnumerator()
にて、送信用データに キャラクターアイコンID
を追加で登録します。
private IEnumerator SendScoreEnumerator()
{
sendScoreButton.interactable = false;
highScoreLabel.text = "送信中...";
//ハイスコア送信
if (_ncmbRecord == null)
{
_ncmbRecord = new NCMBObject(_board.ClassName);
_ncmbRecord.ObjectId = ObjectID;
}
_ncmbRecord[COLUMN_NAME] = InputtedNameForSave;
_ncmbRecord[COLUMN_SCORE] = _lastScore.Value;
_ncmbRecord[COLUMN_ICON] = _lastIcon; // ← ここ追加
...以下略...
}
ランキング表示
・ RankingNode.cs
にキャラクターアイコン表示用のフィールドIcon
を追加します
public class RankingNode : MonoBehaviour
{
public Text NoText;
public Text NameText;
public Text ScoreText;
public Image Icon; // ← ここ追加
}
・RankingSceneManager.cs
のLoadRankingBoard()
にて、生成したインスタンスに キャラクターアイコンID
を入れます。
private IEnumerator LoadRankingBoard()
{
...以前略...
foreach (var r in so.Result)
{
var n = Instantiate(rankingNodePrefab, scrollViewContent);
var rankNode = n.GetComponent<RankingNode>();
rankNode.NoText.text = (++rank).ToString();
rankNode.NameText.text = r[COLUMN_NAME].ToString();
var iconID = int.Parse(r[COLUMN_ICON].ToString()); // ← ここ追加
rankNode.Icon.sprite = icons[iconID]; // ← ここ追加
var s = _board.BuildScore(r[COLUMN_SCORE].ToString());
rankNode.ScoreText.text = s != null ? s.TextForDisplay : "エラー";
// Debug.Log(r[COLUMN_SCORE].ToString());
}
...以下略...
}
プレハブ、シーン
・RankingNode.prefab
に空のオブジェクトを追加します。
・↑ のオブジェクトに Image
コンポーネントをアタッチします。
・さらに、RankingNode
コンポーネントの Icon 項目に、先ほどのImage
をアタッチします。
・Ranking.unity
シーンを開き、RankingSceneManager
コンポーネントの Icons 項目に、キャラクターアイコン画像を入れておきます。 (キャラクターアイコンIDと画像の順番を合わせておいてください。)
ランキングを開く
こんな感じで開きます。
{
double score = 100d; // ← スコア。ゲーム内のスクリプトから適宜拾ってくる
int icon = 1; // ← 現在使用しているキャラクターのID。ゲーム内のスクリプトから適宜拾ってくる
int board = 0; // ← ランキング番号。ランキングの種類が1つだけなら0
RankingLoader.Instance.SendScoreAndShowRankingWithIcon(score, icon, board);
}
その他、応用
キャラクターアイコン画像のサイズは、 RankingNode.prefab
の Height よりも小さくする必要があります (はみ出さないようにするために)
おそらく、デフォルトの Height のままキャラクターアイコンを表示しようとすると、小さい印象を持つと思います。アイコンを大きく表示するためには、RankingNode.prefab
の Height 値を大きくすると良いでしょう。
参考
・【Unity、WebGL】なるべく簡単にオンラインランキング機能をつけるサンプル
・Unity1Week 参加作品「Accumulate Jump Run」