Unityで作るランキング表示のベストプラクティス


ゲームやアプリにランキングを導入すると、ユーザー同士の競争心を刺激し、継続利用を促す効果があります。本記事では、Unityでランキングを表示する方法を、UI構築・データ構造・更新処理の3つの観点から解説します。単純なサンプルから始め、実際に使いやすいコードへ改良していく流れを追っていきましょう。


UIの準備

ランキングは「縦に並んだリストUI」が基本です。以下の構成でCanvasに配置します。

  • RankingDialog (Panel)
    • ScrollView
      • Viewport
        • Content(縦方向に並べる)
  • RankingButton(Prefab)
    • 名前テキスト
    • スコアテキスト
    • アイコン画像

配置には Vertical Layout Group を利用し、自動整列を行います。

テキストには TextMeshPro を推奨します。可読性と装飾性が高く、今後のUnity開発では必須に近い存在です。


データ構造(ランキングクラス)

シングルトンを使ってランキングデータを集中管理します。

using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public sealed class Ranking
{
    private Ranking() {}
    private static Ranking _instance;
    public static Ranking Instance => _instance ??= new Ranking();

    // ランキングの1件を表すデータ構造
    public sealed class Ranker
    {
        public string Name { get; }
        public Sprite Icon { get; }
        public int Score { get; }
        public Ranker(string name, Sprite icon, int score)
            => (Name, Icon, Score) = (name, icon, score);
    }

    private readonly List<Ranker> _rankers = new();
    public IReadOnlyList<Ranker> Rankers 
        => _rankers.OrderByDescending(r => r.Score).ToList();

    public void Add(string name, Sprite icon, int score)
        => _rankers.Add(new Ranker(name, icon, score));

    public bool Remove(string name)
        => _rankers.Remove(_rankers.Find(r => r.Name == name));

    public void Clear() => _rankers.Clear();
}

UI更新処理

ランキングを表示するUIコントローラです。

using System.Collections.Generic;
using UnityEngine;
using TMPro;
using UnityEngine.UI;

public class RankingDialog : MonoBehaviour
{
    [SerializeField] Transform content;
    [SerializeField] GameObject rankingButtonPrefab;

    private readonly List<GameObject> _buttons = new();

    public void ShowRanking()
    {
        var rankers = Ranking.Instance.Rankers;

        // 差分更新:必要数だけ再利用または生成
        for (int i = 0; i < rankers.Count; i++)
        {
            GameObject button;
            if (i < _buttons.Count)
            {
                button = _buttons[i];
                button.SetActive(true);
            }
            else
            {
                button = Instantiate(rankingButtonPrefab, content);
                _buttons.Add(button);
            }

            var rb = button.GetComponent<RankingButton>();
            rb.Set(rankers[i].Name, rankers[i].Icon, rankers[i].Score);
        }

        // 余分なボタンは非表示
        for (int i = rankers.Count; i < _buttons.Count; i++)
            _buttons[i].SetActive(false);
    }
}

各ボタンの制御

ランキング1件分の表示用Prefab側スクリプトです。

using TMPro;
using UnityEngine;
using UnityEngine.UI;

public class RankingButton : MonoBehaviour
{
    [SerializeField] TMP_Text nameText;
    [SerializeField] TMP_Text scoreText;
    [SerializeField] Image iconImage;

    public void Set(string name, Sprite icon, int score)
    {
        nameText.text = name;
        scoreText.text = score.ToString();
        iconImage.sprite = icon;
    }
}

発展:データ永続化

ランキングを一時的に表示するだけでなく、データ保存・共有にも対応可能です。

  • ローカル保存JsonUtility を利用して Ranker リストをシリアライズ → PlayerPrefsやファイルに保存。
  • ネット同期サーバーAPIと連携すれば、全プレイヤー共通のランキング表示も実現できます。

よくあるハマりポイント

  • TextとTextMeshProの混在開発初期からTMPに統一しておくと混乱を避けられる。
  • Layout Groupのスペルミス“Panel”や“Layout”の綴り間違いでInspector参照が外れることがある。
  • ソートのタイミング「追加時にソート」か「表示時にまとめてソート」か方針を決めておくことが大切。

まとめ

  • ランキング実装の基本は「データの並べ替え」と「UIへの反映」。
  • 本記事では 命名改善・差分更新・TMP統一 を取り入れた完成例を紹介しました。
  • 小規模ならシンプルに、大規模なら責務分離やオブジェクトプールなどを導入しましょう。

ランキングはゲームにおけるモチベーションの源泉です。まずは本記事のサンプルを試し、自身のゲームに合わせてカスタマイズしてみてください。


ni

訪問数 6 回, 今日の訪問数 6回

List,UI,Unity

Posted by hidepon