Menu
CoddyTech

ゲームを保存する

CoddyのUnityジャーニー「Unityにおけるゲームアーキテクチャ」セクションの一部。レッスン 25/50。

セーブデータは、JSONとして書き込まれる1つのオブジェクトです。セーブに必要なすべてを[System.Serializable]クラスに入れ、ゲームから値を設定し、そのオブジェクトのJsonUtility.ToJsonをゲーム終了後も保持される場所に書き込みます。このダンジョンでは、階層、ゴールド、見つけた鍵を保存します。

[System.Serializable]
public class DungeonSave
{
    public int floor;
    public int gold;
    public List<string> keys;
}
using System.Collections.Generic;
using System.IO;
using UnityEngine;

public class Dungeon : MonoBehaviour
{
    public int floor = 1;
    public int gold;
    public List<string> keys = new List<string>();
    private string path;

    void Start()
    {
        path = Path.Combine(Application.persistentDataPath, "dungeon.json");
        if (File.Exists(path))
        {
            DungeonSave save = JsonUtility.FromJson<DungeonSave>(File.ReadAllText(path));
            floor = save.floor;
            gold = save.gold;
            keys = save.keys;
        }
    }

    public void Save()
    {
        DungeonSave save = new DungeonSave();
        save.floor = floor;
        save.gold = gold;
        save.keys = keys;
        File.WriteAllText(path, JsonUtility.ToJson(save));
    }
}

Application.persistentDataPathは、Unityがすべてのプラットフォームでゲームに提供するフォルダーで、ゲームを終了しても、アップデート後も保持されます。Path.Combineは、プラットフォームの区切り文字を使って、このフォルダーとファイル名を結合します。File.WriteAllText(path, text)は古いファイルがあれば置き換えて書き込み、File.Existsはファイルが存在するかどうかを返し、File.ReadAllTextはファイルを読み込みます(これら3つはすべてSystem.IOにあります)。ゲーム本体のフォルダーは読み取り専用の場合があるため、セーブデータはpersistentDataPathに保存し、それ以外の場所には保存しません。パスはAwakeまたはStartで組み立ててください。Unityでは、フィールド初期化子でpersistentDataPathを使うことはできません。

セーブ用クラスにはセーブに必要なものだけを入れ、ゲーム内の値をそこにコピーして保存し、読み込み時にはそこから値をコピーします。小さなセーブデータなら、ファイルの代わりにPlayerPrefsに保存できます。PlayerPrefs.SetString("dungeon", json)とPlayerPrefs.GetString("dungeon")で、同じJSONを保存できます。チェックポイントやSaveボタンからなど、残しておく価値のあることが起きたときにセーブしてください。通常の終了時にはOnApplicationQuitが実行されますが、スマートフォンではバックグラウンドのゲームがこの処理を経ずに終了することがあります。

challenge icon

チャレンジ

中級

探検者は矢印キーで島を歩き、Spaceキーを押すと探検者のいる場所に旗を立てます。島をファイル island.json に保存されるゲームデータにしましょう:

  • IslandSave.cs に、[System.Serializable] を付けたクラス IslandSave を記述し、public フィールドとして playerPosition(Vector3)と flags(List<Vector3>)を用意します。
  • Save ボタンから呼び出される Save() は、探検者の位置と旗をJSONとして、Application.persistentDataPath 内の island.json に書き込みます。
  • Start() で、island.json が存在する場合は、探検者を保存された位置に戻し、保存された旗をすべて再び立てます。旗が次回の保存時にもリストに含まれるよう、PlantFlag を使います。

Play を押し、旗をいくつか立てて Save をクリックし、その後 Stop を押してから、もう一度 Play を押します。それから Check を押してください。

自分で試してみよう

using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.InputSystem;

public class Explorer : MonoBehaviour
{
    public GameObject flagPrefab;
    public float speed = 4f;
    private List<Vector3> flags = new List<Vector3>();
    private InputAction moveAction;

    void Start()
    {
        moveAction = InputSystem.actions.FindAction("Move");
        // ここで island.json を読み込む
    }

    void Update()
    {
        Vector2 input = moveAction.ReadValue<Vector2>();
        transform.Translate(new Vector3(input.x, 0f, input.y) * speed * Time.deltaTime);
        if (Keyboard.current.spaceKey.wasPressedThisFrame)
        {
            PlantFlag(transform.position);
        }
    }

    void PlantFlag(Vector3 position)
    {
        flags.Add(position);
        Instantiate(flagPrefab, new Vector3(position.x, 0.5f, position.z), Quaternion.identity);
    }

    // Save ボタンから呼び出される
    public void Save()
    {
        // プレイヤーの位置と旗を island.json に書き込む
    }
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

Unityにおけるゲームアーキテクチャのすべてのレッスン