この記事の要旨
定番アセット”EasySave3″を使って、シンプルなハイスコアの記録と表示の機能を作る。記録や読み込みのタイミングは”Arbor3″でのステート管理を利用。概観
下記の3つのクラスで実装しました。- ScoreManager.cs
- 一回のプレイのスコアを記録するクラス
- HighScoreManager.cs
- 上記のスコアを、保存されているハイスコアと比較し、必要なら上書きして保存するクラス
- HighScoreDescriber.cs
- 保存されたハイスコアをUI上に表示するクラス
一回のプレイのスコアを記録する
みなさん各自のゲームで実装されていると思うので参考程度に。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
public class ScoreManager : MonoBehaviour { public int Score { get; private set; } TextMeshProUGUI petalNum; ComboBonus comboBonus; HighScoreManager highScoreManager; HighScoreDescriber highScoreDescriber; void Start() { petalNum = GameObject.Find("PetalNum").GetComponent<TextMeshProUGUI>(); petalNum.text = "0"; comboBonus = GameObject.Find("Combo").GetComponent<ComboBonus>(); highScoreManager = GetComponent<HighScoreManager>(); } [Button] public void AddScore(int score) { int bonusRate = comboBonus.Rate(); Score += score * bonusRate; petalNum.text = Score.ToString(); } //arborでResultステートに入ったタイミングで呼ぶ public void RefreshLevel1HighScore() { highScoreDescriber = GameObject.Find("View - Ranking(Clone)").GetComponent<HighScoreDescriber>(); List<int> currentHighScores = highScoreManager.CheckLevel1HighScore(Score); highScoreDescriber.DescribeHighScore(currentHighScores); } } |
HighScoreDescriberクラスをStart()でなく独自のタイミングでGetComponentでキャッシュしているのは、HighScoreDescriberクラスを付与したオブジェクトがPrefab化されており、リザルト画面へ遷移したタイミングで生成されるようにしているためです。
生成後のタイミングでRefreshLevel1HighScore()をArborのSendEventGameObjectを使って呼んでいます。
RefreshLevel1HighScore()では、後述する「ハイスコアの更新確認」「UIへの反映」も合わせて呼んでおり、このメソッドがハイスコア周りの処理の根っこになっています。
結果のスコアを、保存されているハイスコアと比較
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
public class HighScoreManager : MonoBehaviour { List<int> defaultHighScores = new List<int> { }; List<int> Level1CurrentScores { get; set; } = new List<int>(); private void Start() { Initialize(); Load(); } [Button] void Initialize() { defaultHighScores = new List<int> { 20, 16, 14, 12, 10, 8, 6, 4, 2, 0 }; Level1CurrentScores = new List<int>(); } [Button] void Load() { Level1CurrentScores = ES3.Load<List<int>>("level1",defaultValue:defaultHighScores); } [Button] public List<int> CheckLevel1HighScore(int currentScore) { int minIndex = Level1CurrentScores.FindIndex(x => x < currentScore); //ランクインしなかった時の例外を潰す必要がある try { Level1CurrentScores.Insert(minIndex, currentScore); Level1CurrentScores.RemoveAt(10); Save(); return Level1CurrentScores; } catch (System.ArgumentOutOfRangeException ex) { Debug.Log("ランク外だったみたいですね"); Save(); return Level1CurrentScores; } } [Button] void Save() { ES3.Save<List<int>>("level1", Level1CurrentScores); } [Button] void Delete() { ES3.DeleteKey("level1"); } } |
Loadメソッドでは、EasySave3に用意されているES3.Loadメソッドを用いて保存されているハイスコアをロードしています。
まずは、FindIndexを用いて、ロードされたハイスコアの中から”結果スコアより大きい値のうち最小値が格納されているインデックス”を探します。
それが存在すれば=ハイスコアにランクインしていれば、Insertで結果スコアを挿入し、はみ出た末尾の要素を削除後、上書きでSaveメソッドを実行します。
存在しなければ例外処理の方に進み、保存されているハイスコアには手を入れずそのまま値を返します。(一応Saveを入れてますがいらなかったかも)
Saveメソッドの中ではEasySave3に用意されているES3.Saveメソッドを用いて、”level1″という名前のキーにハイスコアを保存しています。
保存したハイスコアをUI上で表示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
public class HighScoreDescriber : MonoBehaviour { HighScoreManager highScoreManager; TextMeshProUGUI[] HighScores = new TextMeshProUGUI[3]; int currentScore; //startだとDescribeHighScoreを呼ぶタイミングに間に合ってないっぽい void Awake() { highScoreManager = GameObject.Find("ScoreManager").GetComponent<HighScoreManager>(); HighScores[0] = GameObject.Find("Score1st").GetComponent<TextMeshProUGUI>(); HighScores[1] = GameObject.Find("Score2nd").GetComponent<TextMeshProUGUI>(); HighScores[2] = GameObject.Find("Score3rd").GetComponent<TextMeshProUGUI>(); } public void DescribeHighScore(List<int> Level1CurrentScores) { for (int i = 0; i < 3; i++) { HighScores[i].text = Level1CurrentScores[i].ToString(); } } } |
DescribeHighScoreメソッドで、渡されたハイスコアを頭から3つ、スコア表示用のオブジェクトに放り込んでいます。