【Unity】PlayerPrefsを使ったランキング管理の実装

2024年5月17日

Unityでランキングを管理するために、PlayerPrefsを使用して名前、得点、日時を保存し、得点でソートする方法を紹介します。ゲームを再起動しても記録が残るように実装します。

ランキングデータのクラスを作成する

まず、ランキングデータを保持するためのクラスを作成します。

using System;

[Serializable]
public class RankingEntry
{
    public string name;
    public int score;
    public DateTime date;

    public RankingEntry(string name, int score, DateTime date)
    {
        this.name = name;
        this.score = score;
        this.date = date;
    }
}

ランキングデータの管理クラスを作成する

次に、リストをJSON形式でシリアライズし、それをPlayerPrefsに保存し、読み込む方法を示します。

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

public class RankingManager : MonoBehaviour
{
    private List<RankingEntry> rankingEntries;

    void Awake()
    {
        LoadRanking();
    }

    public void AddRankingEntry(string name, int score)
    {
        RankingEntry newEntry = new RankingEntry(name, score, DateTime.Now);
        rankingEntries.Add(newEntry);
        SaveRanking();
    }

    public List<RankingEntry> GetRankingEntries()
    {
        rankingEntries.Sort((x, y) => y.score.CompareTo(x.score));
        return rankingEntries;
    }

    private void LoadRanking()
    {
        string json = PlayerPrefs.GetString("RankingData", "");
        if (!string.IsNullOrEmpty(json))
        {
            RankingList rankingList = JsonUtility.FromJson<RankingList>(json);
            rankingEntries = rankingList.rankingEntries;
        }
        else
        {
            rankingEntries = new List<RankingEntry>();
        }
    }

    private void SaveRanking()
    {
        rankingEntries.Sort((x, y) => y.score.CompareTo(x.score)); // スコアでソート
        RankingList rankingList = new RankingList { rankingEntries = rankingEntries };
        string json = JsonUtility.ToJson(rankingList);
        PlayerPrefs.SetString("RankingData", json);
        PlayerPrefs.Save();
    }

    [Serializable]
    private class RankingList
    {
        public List<RankingEntry> rankingEntries;
    }
}

ランキングを表示するUIを作成する

TextMeshProを使ってランキングを表示します。

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

public class RankingUI : MonoBehaviour
{
    public RankingManager rankingManager;
    public GameObject rankingEntryPrefab;
    public RectTransform rankingContainer;

    public int maxEntriesToShow = 10;

    void Start()
    {
        DisplayRanking();
    }

    public void DisplayRanking()
    {
        foreach (Transform child in rankingContainer)
        {
            Destroy(child.gameObject);
        }

        List<RankingEntry> rankingEntries = rankingManager.GetRankingEntries();
        for (int i = 0; i < maxEntriesToShow; i++)
        {
            GameObject entryObject = Instantiate(rankingEntryPrefab, rankingContainer);
            if (i < rankingEntries.Count)
            {
                RankingEntry entry = rankingEntries[i];
                entryObject.transform.Find("Name").GetComponent<TextMeshProUGUI>().text = entry.name;
                entryObject.transform.Find("Score").GetComponent<TextMeshProUGUI>().text = entry.score.ToString();
                entryObject.transform.Find("Date").GetComponent<TextMeshProUGUI>().text = entry.date.ToString("yyyy/MM/dd HH:mm");
            }
            else
            {
                entryObject.transform.Find("Name").GetComponent<TextMeshProUGUI>().text = "";
                entryObject.transform.Find("Score").GetComponent<TextMeshProUGUI>().text = "";
                entryObject.transform.Find("Date").GetComponent<TextMeshProUGUI>().text = "";
            }
        }
    }
}

rankingEntryPrefabの作り方

rankingEntryPrefab は、ランキングの各エントリーを表示するためのプレハブです。これを作成するためには、Unityエディタ内でUI要素をデザインし、それをプレハブとして保存する必要があります。以下の手順でrankingEntryPrefab を作成します。

TextMeshProをインポート

まず、TextMeshProを使用するために、UnityのPackage ManagerからTextMeshProをインポートします。

UI要素をデザイン

  1. Hierarchyで右クリックし、UI > Canvasを作成します。
  2. Canvasの子として、右クリックし、UI > Panelを作成します。これがrankingEntryPrefabのベースとなります。
  3. Panelのサイズを調整し、適切な位置に配置します。
  4. Panelの子として、UI > Text - TextMeshProを3つ作成し、それぞれ名前、得点、日時を表示するためのテキストフィールドを作成します。

UI要素の設定

  1. 各TextMeshProオブジェクトを選択し、Inspectorで以下の設定を行います。
    • 名前を設定 (Name, Score, Date など)
    • Anchor, Pivot, Position, Sizeなどを設定し、適切に配置します。
    • TextMeshProコンポーネントの設定(フォント、サイズ、アラインメントなど)を調整します。
  2. Panelオブジェクトにコンポーネントを追加します。
    • Content Size Fitter コンポーネントを追加し、HorizontalとVerticalのFitを Preferred Size に設定します。
    • 必要に応じて Layout Element コンポーネントを追加し、最小サイズや優先サイズを設定します。

プレハブとして保存

  1. 作成したPanelをHierarchyからProjectビューの適切なフォルダにドラッグしてプレハブとして保存します。例えば、Assets/Prefabs フォルダに保存します。
  2. プレハブを保存後、RankingUIスクリプトの rankingEntryPrefab フィールドにドラッグ&ドロップして設定します。

最終的な構造の例

Canvas
└── Panel (rankingEntryPrefab)
    ├── Text (TextMeshPro) - Name
    ├── Text (TextMeshPro) - Score
    └── Text (TextMeshPro) - Date

インターフェースの構築

Unityエディタ内で、以下の手順でインターフェースを構築します。

  1. RankingManagerRankingUITestRankingの各スクリプトを適切なゲームオブジェクトにアタッチします。
  2. RankingUIスクリプト内のrankingEntryPrefabrankingContainerを設定します。
    rankingContainerには、Panelを設定します

これで、PlayerPrefsを使ってリストをJSON形式で保存し、TextMeshProを使用して復元する方法が実装できます。ゲームの終了時にデータがPlayerPrefsに保存され、次回のゲーム開始時にランキングが復元されます。

using UnityEngine;

public class TestRanking : MonoBehaviour
{
    public RankingManager rankingManager;
    public RankingUI rankingUI;

    void Start()
    {
        // サンプルデータを追加
        rankingManager.AddRankingEntry("Player1", 100);
        rankingManager.AddRankingEntry("Player2", 200);
        rankingManager.AddRankingEntry("Player3", 150);

        // UIを更新して表示
        rankingUI.DisplayRanking();
    }
}

Unity

Posted by hidepon