Unity初心者が2Dタワーディフェンスを作っています。
今回は、ゲームデータのセーブとロード機能を実装します。前回実装したステージのクリア済みフラグとハイスコアをセーブします。
- Mac mini (M1, 2020)
- Unity 2022.3.36f1
- Easy Save 3.5.23
Easy Saveを使う
今回は、Unityでデータのセーブ・ロードをするときの定番アセットEasy Saveを使います。有料です。お高いです。64.90ドルです。日本円で壱萬円弱です(時価)。私は去年のブラックフライデーに半額で購入しました。セールを狙いましょう。
でもそれだけの対価を払う価値がありまして、あらゆる型のデータをセーブできるし、データの暗号化や圧縮もできる優れモノなのです。

Easy Saveのインポート
まず、ゲームにEasy Saveをインポートします。
すでにアセットストアでEasy Saveを購入済みで、My Assetsに追加されている前提で進めます。
Unityエディタのメニューで「Window > Package Manager」を選択します。

Package Managerウインドウが開くので、左上のドロップダウンリストで「My Assets」を選択します。

My Assetsのアセット一覧が表示されるのでEasy Saveを選択して、「Download」ボタンをクリックします。

ダウンロードが終わったら「Import」ボタンをクリックします。

Import Unity Packageウインドウが開くので「Import」をクリックします。

以上でEasy Saveのインポートが完了しました。いえい。
Easy Saveの設定
Unityエディタのメニューで「Window > Easy Save 3」を選択します。

Easy Saveウインドウが開きます。「Settings」タブで各種設定を変更できます。

「Encryption」と「Encryption Password」を設定して、データが暗号化されるようにしました。
データのセーブ
セーブするデータはUserDataスクリプトで定義しているstageUserDataList
です。このリストには各ステージのステージID、ハイスコア、クリア済みフラグが入っています。
どのタイミングでセーブするかというと、ハイスコアが更新されたときとクリア済みフラグが更新されたときですね。
UserDataスクリプトを修正します。
using System;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 各ステージのハイスコアとクリア情報を格納するデータ構造
/// </summary>
[Serializable]
public class StageUserData
{
public int stageId;
public int highScore;
public bool isCleared;
}
/// <summary>
/// ユーザーの進行状況を管理するクラス
/// </summary>
public class UserData : MonoBehaviour
{
// 各ステージのデータリスト
public List<StageUserData> stageUserDataList = new List<StageUserData>();
public static UserData Instance { get; private set; }
// ...省略...
/// <summary>
/// ハイスコアを更新
/// </summary>
public void UpdateHighScore(int stageId, int score)
{
var data = GetStageData(stageId);
if (score > data.highScore)
{
data.highScore = score;
// ここから追加
ES3.Save("stageUserDataList", stageUserDataList);
// ここまで
}
}
/// <summary>
/// クリア情報を更新
/// </summary>
public void SetStageCleared(int stageId)
{
var data = GetStageData(stageId);
data.isCleared = true;
// ここから追加
ES3.Save("stageUserDataList", stageUserDataList);
// ここまで
}
}
UpdateHighScore()
とSetStageCleared()
にstageUserDataList
をセーブする処理を追加しました。
データのロード
データをロードするタイミングは、ゲーム状態がTitleになったとき(のタイトルパネルの表示処理よりも前)にします。
というのは、ロードしたデータをタイトルパネルに反映させる必要があるからですね。
UserDataスクリプトを修正します。
using System;
using System.Collections.Generic;
using UnityEngine;
// ...省略...
/// <summary>
/// ユーザーの進行状況を管理するクラス
/// </summary>
public class UserData : MonoBehaviour
{
// ...省略...
// ここから追加
/// <summary>
/// ユーザーデータをロード
/// </summary>
public void Load()
{
if (ES3.KeyExists("stageUserDataList"))
{
stageUserDataList = ES3.Load<List<StageUserData>>("stageUserDataList");
}
}
// ここまで
}
データをロードするメソッドLoad()
を追加しました。
GameManagerスクリプトを修正します。
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI; // Buttonクラスを使用するために必要
using System.Collections; // IEnumeratorを使用するために必要
using TMPro; // TextMeshProを使うために必要
public class GameManager : MonoBehaviour
{
// ...省略...
private void Start()
{
// ボタンのクリックイベントを登録
startPauseButton.onClick.AddListener(OnStartPauseButtonClicked);
restartButton.onClick.AddListener(OnRestartButtonClicked);
// ここから追加
// ゲーム状態を Title に設定
ChangeState(GameState.Title);
// ここまで
// ゲーム開始時にゲーム状態が Title の場合、時間を停止
if (CurrentState == GameState.Title)
{
Time.timeScale = 0; // 時間を停止
}
}
/// <summary>
/// ゲーム状態を変更する
/// </summary>
/// <param name="newState">新しいゲーム状態</param>
public void ChangeState(GameState newState)
{
previousState = CurrentState; // 前の状態を保存
CurrentState = newState;
switch (newState)
{
case GameState.Title:
Debug.Log("ゲーム状態: Title");
// ここから追加
// データをロード
if (UserData.Instance != null)
{
UserData.Instance.Load();
}
// ここまで
Time.timeScale = 0; // 時間を停止
titlePanel.SetActive(true); // タイトルパネルを表示
titlePanel.transform.SetAsLastSibling(); // タイトルパネルを最前面に移動
pausePanel.SetActive(false); // ポーズパネルを非表示
gameOverPanel.SetActive(false); // ゲームオーバーパネルを非表示
nextWaveButton.interactable = false; // 次のウェーブボタンを非活性化
stageClearPanel.SetActive(false); // ステージクリアパネルを非表示
UpdateStageSelectButtons(); // ステージ選択ボタンの有効/無効を更新
break;
// ...省略...
}
// ...省略...
}
ChangeState()
内でゲーム状態がTitleになったときにデータをロードする処理を追加しました。
ゲーム起動時にもロードしたデータを反映させるために、Start()
内でChangeState(GameState.Title)
しました。
さいごに
ゲームデータのセーブとロード機能を実装したことで、ゲームを終了してもステージクリア状況やハイスコアが保持されるようになりました。
以上で、ゲームの基本的な仕組みは完成したんじゃないかと思います。あとはゲームを華やかにするためのギミックを追加していきたいです。
でわでわ
コメント