Parallels Desktop 35%OFF セール

【Unity】タワーディフェンス(22) データのセーブとロード【クソゲー制作】

タワーディフェンスを作る(22)

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に追加されている前提で進めます。

STEP

Unityエディタのメニューで「Window > Package Manager」を選択します。

タワーディフェンス224
STEP

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

タワーディフェンス225
STEP

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

タワーディフェンス226
STEP

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

タワーディフェンス227
STEP

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

タワーディフェンス228

以上でEasy Saveのインポートが完了しました。いえい。

Easy Saveの設定

STEP

Unityエディタのメニューで「Window > Easy Save 3」を選択します。

タワーディフェンス229
STEP

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

タワーディフェンス230

「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になったとき(のタイトルパネルの表示処理よりも前)にします。

というのは、ロードしたデータをタイトルパネルに反映させる必要があるからですね。

STEP

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()を追加しました。

STEP

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)しました。

さいごに

ゲームデータのセーブとロード機能を実装したことで、ゲームを終了してもステージクリア状況やハイスコアが保持されるようになりました。

以上で、ゲームの基本的な仕組みは完成したんじゃないかと思います。あとはゲームを華やかにするためのギミックを追加していきたいです。

でわでわ

タワーディフェンスを作る(22)

この記事が気に入ったら
いいね または フォローしてね!

シェアしてね

コメント

コメントする

目次