前回の記事ではセーブ機能を追加しました。
前回の記事:
2DRPGの作り方25 PlayerPrefsとjsonを用いてセーブ機能を実装する
前回の記事でゲームオーバーとゲームクリア処理を作成しました。前回の記事:今回の記事ではUnityのPlayerPrefsとjsonデータ構造を用いてセーブシステムを作成していきます。また、宝箱とボスの配置状況も記録し、前回のゲームオーバー処...
今回の記事ではセーブしたデータをロードできるようにしていきます。
また、宝箱を取得した後にゲームオーバーになってしまった場合、一度取得した宝箱を何度でも取得できる不具合もここで調整していきます。
ロード機能を追加する
それではまず「SaveData」コンポーネントにロード機能を追加していきます。
次のように「SaveData」コンポーネントを修正してください。
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 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
// SaveData.cs ロード機能の追加 //次のものを追加 [SerializeField] List<Map> _maps; public bool NowLoading { get; private set; } = false; public bool IsSuccessLoad { get; private set; } = false; public void Load(RPGSceneManager manager) { StopAllCoroutines(); StartCoroutine(LoadCoroutine(manager)); } IEnumerator LoadCoroutine(RPGSceneManager manager) { IsSuccessLoad = false; NowLoading = false; if (!PlayerPrefs.HasKey("player")) { Debug.LogError("Fail to Load saveData"); yield break; } NowLoading = true; var mapName = PlayerPrefs.GetString("activeMap"); var loadMap = _maps.Find(_map => _map.name.Replace("(Clone)", "") == mapName); if (loadMap == null) { Debug.LogError($"Fail to find map({mapName})... "); yield break; } DeleteTemporarySaveDatas(); Object.Destroy(manager.ActiveMap.gameObject); manager.ActiveMap = Object.Instantiate(loadMap); yield return null; var player = manager.Player; player.LoadSaveData(PlayerPrefs.GetString("player")); var instantMapData = JsonUtility.FromJson<Map.InstantSaveData>(PlayerPrefs.GetString("instantMapData")); manager.ActiveMap.Load(instantMapData); var mapData = JsonUtility.FromJson<Map.SaveData>(PlayerPrefs.GetString($"map_{mapName}")); manager.ActiveMap.Load(mapData); NowLoading = false; IsSuccessLoad = true; } public void LoadSaveData(Map map) { var key = $"map_{map.name.Replace("(Clone)", "")}"; var tempKey = "temp_" + key; if (PlayerPrefs.HasKey(tempKey)) { Debug.Log($"{map.name}: Load Temp SaveData\n{PlayerPrefs.GetString(tempKey)}"); var mapData = JsonUtility.FromJson<Map.SaveData>(PlayerPrefs.GetString(tempKey)); map.Load(mapData); } else if(PlayerPrefs.HasKey(key)) { Debug.Log($"{map.name}: Load SaveData \n{PlayerPrefs.GetString(key)}"); var mapData = JsonUtility.FromJson<Map.SaveData>(PlayerPrefs.GetString(key)); map.Load(mapData); } } private void Awake() { DeleteTemporarySaveDatas(); } public void DeleteTemporarySaveDatas() { foreach (var map in _maps) { var key = $"temp_map_{map.name.Replace("(Clone)", "")}"; PlayerPrefs.DeleteKey(key); } } |
セーブデータの読み込み機能を「SaveData」コンポーネントに追加したので、次は「Map」および「CharacterBase」コンポーネントにセーブデータの読み込み機能を追加していきます。
一時的なセーブ機能について
ここまででセーブ機能は大体できました。
ただし、現状のままだとセーブしていない拾ったアイテムなどの状態が記録されない状態になっています。
戦闘に負けた時にマップが切り替わるとアイテムが復活して、何回でもアイテムが取れるようになるなどの問題が出てしまいます・・・
この問題を修正するには次の箇所でマップの状態を一時的に記録するようにします。
- 戦闘開始時
- マップ切り替え時
基本的にセーブに影響する行動を行った時に記録するようにすればOKです。実際にここで対策を行いましょう。
それではまず「BattleWindow」コンポーネントを次のように修正してください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
// BattleWindow.cs 戦闘開始時にマップの状態を一時的に記録する //次のものを修正 public override void Open() { var saveData = Object.FindObjectOfType<SaveData>(); saveData.SaveTemporary(RPGSceneManager.ActiveMap); base.Open(); MainCommands.Index = 0; DoEscape = false; Items.gameObject.SetActive(false); Description.transform.parent.gameObject.SetActive(false); UpdateUI(); Encounter = UseEncounter.Clone(); SetupEnemies(); } |
次に「MoveMapEvent」クラスを次のように修正してください。
イベントを発生するたびに移動する前のマップの状態を一時的に記録するようにしています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
// MoveMapEvent.cs //次のものを修正 public override void Exec(RPGSceneManager manager) { var saveData = Object.FindObjectOfType<SaveData>(); saveData.SaveTemporary(manager.ActiveMap); Object.Destroy(manager.ActiveMap.gameObject); manager.ActiveMap = Object.Instantiate(MoveMapPrefab); if(manager.ActiveMap.FindMassEventPos(StartPosTile, out var pos)) { manager.Player.SetPosNoCoroutine(pos); manager.Player.CurrentDir = StartDirection; } } |
最後にマップ読み込みの時に一時的に保存しているデータがないか確認し、あればそれを読み込むようにします。
1 2 3 4 5 6 7 8 9 10 |
// Map.cs 一時的なセーブデータの確認 //次のものをファイル先頭に追加 using GlobalSaveData = SaveData; //次のものを追加 private void Start() { var saveData = Object.FindObjectOfType<GlobalSaveData>(); saveData.LoadSaveData(this); } |
まとめ
今回の内容をまとめると以下のようになります。
- セーブの読み込み機能を追加
- 「CharacterBase」コンポーネントおよびその派生クラスをセーブの読み込み機能に対応
- マップの一時的なセーブ機能を実装
それでは次の記事に行ってみましょう!
2DRPGの作り方27 タイトル画面の作成とシーン間遷移処理を作成してRPG完成!
前回まででセーブ&ロード処理を作りました。前回の記事:今回の記事ではついに2DRPG最後の仕上げとしてタイトル画面を実装していきます。タイトル画面表示スクリプトの作成それではまずスクリプトの方を作成していきます。「TitleMenu.cs」...
コメント