[Unity]ランキングの表示

2022年10月25日

このチュートリアルは次の内容に続きなります

実行イメージ

起動直後にランキングリストに登録されている情報をUIに表示しています
スペースキーを押下すると更新されたランキングが表示されます

シーンの構成

マネージャオブジェクト

ランキングを更新するためのマネージャオブジェクトです
仮にランカー(ユーザー)ごとのイラストを入れています

ランキングボード

ランキングを表示するCanvasです

ランキングを表示するためにエリア

ランカーを表示するためのエリアを設定しています
Panalになります

エリアの大きさの変更

レイアウトグループの調整

ランキングボタン

個別のランキング情報を表示しています
将来、クリックすると詳細表示もできるようにButtonにしています

ランカーの枠の大きさを指定します

ランカーの情報表示欄を登録します

ランカーイメージアイコン(イラスト)

ランカーのイメージアイコンを表示するエリアです
Imageを貼り付けています

ランカーの名前

ランカーの名前表示エリアです
Textになっています

ランカーのスコア

ランカーのスコア表示エリアです
Textになっています

コード

Ranking

ランキング一覧を管理するスクリプトです
シングルトンで構成され複数のインスタンスの作成はされません

内部クラスに個別のランカー情報を持っています

外部からはリストを取得することができます

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

public class Ranking
{
    Ranking()
    {
    }

    static Ranking instance;

    public static Ranking GetInstance
    {
        get
        {
            if (instance == null)
            {
                instance = new Ranking();
            }
            return instance;
        }
    }

    public class Ranker
    {
        public string name;
        public Sprite sprite;
        public int score;

        public Ranker(string name, Sprite sprite, int score)
        {
            this.name = name;
            this.sprite = sprite;
            this.score = score;
        }
    }

    List<Ranker> rankers = new List<Ranker>();

    public List<Ranker> Rankers => rankers.OrderByDescending(ranker => ranker.score).ToList();

    public void Add(string name, Sprite sprite, int score)
    {
        Ranker ranker = new Ranker(name, sprite, score);
        rankers.Add(ranker);
    }

    public void Remove(string name)
    {
        rankers.Remove(rankers.Find(score => score.name == name));
    }

    public void Clear()
    {
        rankers.Clear();
    }
}

RankingDialog

ランキング表示用のエリアにランカーボタンを作成する役割があります

各ランカーは、インスタンスの作成で構成されています
単に追加していますが、LayoutGroupのコンポーネントにより自動的に均等表示されます

using System.Collections.Generic;
using UnityEngine;

public class RankingDialog : MonoBehaviour
{
    [SerializeField]
    int buttonNumber = 10;

    [SerializeField]
    RankingButton rankingButton;


    RankingButton[] rankingButtons;


    private void Awake()
    {
        CreateButton();
    }

    private void CreateButton()
    {
        for (int i = 0; i < buttonNumber - 1; i++)
        {
            Instantiate(rankingButton, transform);
        }

        rankingButtons = GetComponentsInChildren<RankingButton>();
    }

    public void ShowRanking()
    {
        List<Ranking.Ranker> rankers = Ranking.GetInstance.Rankers;

        for (int i = 0; i < rankers.Count; i++)
        {
            rankingButtons[i].Ranker = rankers[i];
        }
    }
}

説明

ランカーごとのボタンの生成します
登録されたボタンの数(buttonNumber)分まで繰り返されます

private void CreateButton()
{
    for (int i = 0; i < buttonNumber - 1; i++)
    {
        Instantiate(rankingButton, transform);
    }
}

子オブジェクトにアタッチされているRankingButtonスクリプトを配列で取得します
この先使いたいのはこのスクリプトのメンバーなのでオブジェクト自体を取得しなくても良いです

rankingButtons = GetComponentsInChildren<RankingButton>();

ランキングを表示します(実際はランカーのボタンを表示します)
ランカー一覧は、RankingクラスのRankersプロパティに保存されています
このクラスから作られるインスタンスは1つで十分なのでシングルトンの呼び出しを使って取得しています

その後、所得した一覧情報を順番に子オブジェクトから取得したスクリプトのRankerプロパティに代入(セット)して行っています

public void ShowRanking()
{
    List<Ranking.Ranker> rankers = Ranking.GetInstance.Rankers;

    for (int i = 0; i < rankers.Count; i++)
    {
        rankingButtons[i].Ranker = rankers[i];
    }
}

RankingButton

ランカー個人の情報を表示するボタンを管理しています
オブジェクトがボタンなので、将来クリックすることで何かを実行できるようにすることもできます
ボタンに表示される情報は、ランカー個人アイコン・名前・得点になります
それぞれに設定するように

using UnityEngine;
using UnityEngine.UI;

public class RankingButton : MonoBehaviour
{
    [SerializeField]
    Image icon;

    [SerializeField]
    Text nameText;

    [SerializeField]
    Text scoreText;

    Ranking.Ranker ranker;

    public Ranking.Ranker Ranker
    {
        get
        {
            return ranker;
        }
        set
        {
            ranker = value;
            icon.sprite = ranker.sprite;
            nameText.text = ranker.name;
            scoreText.text = ranker.score.ToString();
        }
    }
}

説明

Ranking.Ranker ranker;

Rankerクラスの情報は、Rankingクラスのインナークラス(クラス内部に記述されたクラス)なので、.(ピリオド、点)で繋いで表現します

内部クラスでない場合だと単に次のようになりますね

Ranker ranker;

UIの各情報(画像イメージ・名前・スコア)に表示する処理を担っています
Rankerプロパティに代入(セット)すること(setが呼ばれる)で、表示されるようになります

Rankerプロパティは、Ranking.Ranker型なので、valueには3つの情報が渡されます

public Ranking.Ranker Ranker
{
    set
    {
        ranker = value;
        icon.sprite = ranker.sprite;
        nameText.text = ranker.name;
        scoreText.text = ranker.score.ToString();
    }
}

このプロパティに代入するのは、RankingDialogクラスのShowRankingメソッドになります
for文で繰り返し、順番に代入されます

rankingButtons[i].Ranker = rankers[i];

マネージャ

マネージャーは、ゲームを進行をコントロールする役割があるとします
ゲームオーバーになった際、プレイヤーの得点をもとにランキング管理のためのデータを作成します
プレイヤーの情報としては、クラスで、名前・アイコン・得点をメンバーとして管理しています

using UnityEngine;

public class Sample : MonoBehaviour
{
    [SerializeField]
    Sprite[] sprites;

    [SerializeField]
    RankingDialog rankingDialog;

    void Start()
    {
        Ranking ranking = Ranking.GetInstance;
        ranking.Add("太郎", sprites[0], 70);
        ranking.Add("次郎", sprites[1], 60);
        ranking.Add("三郎", sprites[2], 50);

        ranking.Remove("次郎");

        ranking.Add("四郎", sprites[4], 65);

        foreach (var ranker in ranking.Rankers)
        {
            Debug.Log($"名前:{ranker.name}  ポイント:{ranker.score}");
        }

        rankingDialog.ShowRanking();
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            UpdateRanking();

            rankingDialog.ShowRanking();
        }
    }

    private void UpdateRanking()
    {
        Ranking ranking = Ranking.GetInstance;
        ranking.Clear();
        ranking.Add("五郎", sprites[0], 75);
        ranking.Add("六郎", sprites[1], 88);
        ranking.Add("七郎", sprites[2], 20);

        ranking.Remove("七郎");

        ranking.Add("八郎", sprites[3], 10);

        foreach (var ranker in ranking.Rankers)
        {
            Debug.Log($"名前:{ranker.name}  ポイント:{ranker.score}");
        }
    }
}

Unity

Posted by hidepon