Forum begins after the advertisement:
[Part 7] Map problem
Home › Forums › Video Game Tutorial Series › Creating a Metroidvania in Unity › [Part 7] Map problem
- This topic has 70 replies, 4 voices, and was last updated 2 months, 1 week ago by MI NI.
-
AuthorPosts
-
August 9, 2024 at 8:52 pm #15549::
MapManager.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class MapManager : MonoBehaviour { [SerializeField] GameObject[] maps; SavePoint savePoint; private void OnEnable() { savePoint = FindObjectOfType<SavePoint>(); SaveData.Instance.LoadMapData(); UpdateMap(); /* if (savePoint != null) { if(savePoint.interacted) { } } */ } void UpdateMap() { //var savedScenes = SaveData.Instance.sceneName; var savedScenes = SaveData.Instance.mapName; for (int i = 0; i < maps.Length ; i++) { if(savedScenes.Contains("Stage_" + (i + 1))) //此處為地圖名稱 { maps[i].SetActive(true); Debug.Log(savedScenes.Contains("Stage_" + (i + 1))); } else { maps[i].SetActive(false); Debug.Log(savedScenes.Contains("Stage_" + (i + 1))); } } } }
SaveData.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; using System.IO; using UnityEngine.SceneManagement; [System.Serializable] public struct SaveData { public static SaveData Instance; //map stuff public HashSet<string> sceneName; public HashSet<string> mapName; //savePoint stuff public string savePointSceneName; public Vector2 savePointPos; //player stuff public float playerHealth; public float playerMana; public Vector2 playerPosition; public string lastScene; //player skill public bool playerUnlockWallJump; public bool playerUnlockDash; public bool playeUnlockAirJump; public bool playerUnlockSideSpell; public void Initialize() //初始化 { /* //檢查場景文件是否存在,否則將建立一個新文件 if (!File.Exists(Application.persistentDataPath + "/save.scenes.data")) { using (BinaryWriter writer = new BinaryWriter(File.Create(Application.persistentDataPath + "/save.scenes.data"))) { writer.Write(0); // Write an empty scene data structure } } //檢查場景文件是否存在,否則將建立一個新文件 if (!File.Exists(Application.persistentDataPath + "/save.maps.data")) { using (BinaryWriter writer = new BinaryWriter(File.Create(Application.persistentDataPath + "/save.maps.data"))) { writer.Write(0); // Write an empty scene data structure } } */ if (!File.Exists(Application.persistentDataPath + "/save.scenes.data")) { BinaryWriter writer = new BinaryWriter(File.Create(Application.persistentDataPath + "/save.scenes.data")); } if (!File.Exists(Application.persistentDataPath + "/save.maps.data")) { BinaryWriter writer = new BinaryWriter(File.Create(Application.persistentDataPath + "/save.maps.data")); } //檢查重生點文件是否存在,否則將建立一個新文件 if (!File.Exists(Application.persistentDataPath + "/save.savePoint.data")) { BinaryWriter writer = new BinaryWriter(File.Create(Application.persistentDataPath + "/save.savePoint.data")); } //檢查玩家文件是否存在,否則將建立一個新文件 if (!File.Exists(Application.persistentDataPath + "/save.player.data")) { BinaryWriter writer = new BinaryWriter(File.Create(Application.persistentDataPath + "/save.player.data")); } if (sceneName == null) //檢查此場景是否為空 { //如果是,建立一個新HashSet sceneName = new HashSet<string>(); } if (mapName == null) //檢查此場景是否為空 { //如果是,建立一個新HashSet mapName = new HashSet<string>(); } } public void SavedSavePoint() { using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(Application.persistentDataPath + "/save.savePoint.data"))) { Debug.Log("SavedSavePoint by SaveData.cs"); writer.Write(savePointSceneName); writer.Write(savePointPos.x); writer.Write(savePointPos.y); } } public void LoadSavePoint() { //if(File.Exists(Application.persistentDataPath + "/save.savePoint.data")) string savePath = Application.persistentDataPath + "/save.savePoint.data"; if(File.Exists(savePath) && new FileInfo(savePath).Length > 0) { using (BinaryReader reader = new BinaryReader(File.OpenRead(Application.persistentDataPath + "/save.savePoint.data"))) { Debug.Log("LoadSavePoint by SaveData.cs"); savePointSceneName = reader.ReadString(); savePointPos.x = reader.ReadSingle(); savePointPos.y = reader.ReadSingle(); } } else { Debug.Log("SavePoint do not exits by SaveData.cs"); } } public void SavePlayerData() //備註:存儲的順序需與讀取的順序相同,否則可能出錯 { using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(Application.persistentDataPath + "/save.player.data"))) { //血量、魔力 playerHealth = PlayerController.Instance.Health; writer.Write(playerHealth); playerMana = PlayerController.Instance.Mana; writer.Write(playerMana); //技能 playerUnlockWallJump = PlayerController.Instance.unlockWallJump; writer.Write(playerUnlockWallJump); playerUnlockDash = PlayerController.Instance.unlockDash; writer.Write(playerUnlockDash); playeUnlockAirJump = PlayerController.Instance.unlockAirJump; writer.Write(playeUnlockAirJump); playerUnlockSideSpell = PlayerController.Instance.unlockSideSpell; writer.Write(playerUnlockSideSpell); //位置 playerPosition = PlayerController.Instance.transform.position; writer.Write(playerPosition.x); writer.Write(playerPosition.y); //場景 lastScene = SceneManager.GetActiveScene().name; writer.Write(lastScene); } } public void LoadPlayerData() { //string savePath = Application.persistentDataPath + "/save.player.data"; //if (File.Exists(savePath) && new FileInfo(savePath).Length > 0) if(File.Exists(Application.persistentDataPath + "/save.player.data")) { using (BinaryReader reader = new BinaryReader(File.OpenRead(Application.persistentDataPath + "/save.player.data"))) { //血量、魔力 playerHealth = reader.ReadSingle(); playerMana = reader.ReadSingle(); //技能 playerUnlockWallJump = reader.ReadBoolean(); playerUnlockDash = reader.ReadBoolean(); playeUnlockAirJump = reader.ReadBoolean(); playerUnlockSideSpell = reader.ReadBoolean(); //位置 playerPosition.x = reader.ReadSingle(); playerPosition.y = reader.ReadSingle(); //場景 lastScene = reader.ReadString(); Debug.Log(lastScene + "LoadPlayerData by SaveData.cs"); SceneManager.LoadScene(lastScene); PlayerController.Instance.transform.position = playerPosition; PlayerController.Instance.Health = playerHealth; PlayerController.Instance.Mana = playerMana; PlayerController.Instance.unlockWallJump = playerUnlockWallJump; PlayerController.Instance.unlockDash = playerUnlockDash; PlayerController.Instance.unlockAirJump = playeUnlockAirJump; PlayerController.Instance.unlockSideSpell = playerUnlockSideSpell; } Debug.Log("load player data"); } else { //如果檔案不存在 Debug.Log("File doesnt exist"); PlayerController.Instance.Health = PlayerController.Instance.maxHealth; PlayerController.Instance.Mana = 0.5f; PlayerController.Instance.unlockWallJump = false; PlayerController.Instance.unlockDash = false; PlayerController.Instance.unlockAirJump = false; PlayerController.Instance.unlockSideSpell = false; } } public void SaveSceneData() { using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(Application.persistentDataPath + "/save.scenes.data"))) { Debug.Log("SaveScene bySavedata.cs"); writer.Write(sceneName.Count); foreach (string sceneName in sceneName) { writer.Write(sceneName); } } } public void LoadSceneData() { if (File.Exists(Application.persistentDataPath + "/save.scenes.data")) { using (BinaryReader reader = new BinaryReader(File.OpenRead(Application.persistentDataPath + "/save.scenes.data"))) { int sceneCount = reader.ReadInt32(); //sceneName = new HashSet<string>(); for (int i = 0; i < sceneCount; i++) { string _sceneName = reader.ReadString(); sceneName.Add(_sceneName); } } } else { sceneName = new HashSet<string>(); } } public void SaveMapData() { using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(Application.persistentDataPath + "/save.maps.data"))) { Debug.Log("Savemaps bySavedata.cs"); mapName = sceneName; writer.Write(mapName.Count); foreach (string mapName in mapName) { writer.Write(mapName); } } } public void LoadMapData() { if (File.Exists(Application.persistentDataPath + "/save.maps.data")) { using (BinaryReader reader = new BinaryReader(File.OpenRead(Application.persistentDataPath + "/save.maps.data"))) { int mapCount = reader.ReadInt32(); for (int i = 0; i < mapCount; i++) { string _mapName = reader.ReadString(); mapName.Add(_mapName); Debug.Log(_mapName); } } } else { mapName = new HashSet<string>(); } } }
GameManager.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; public class GameManager : MonoBehaviour { public string transitionedFromScene; //儲存前一個場景 public Vector2 platformingRespawnPoint; //重生點 public Vector2 respawnPoint; [SerializeField] SavePoint savePoint; [SerializeField] private FadeUI pauseMenu; [SerializeField] private float fadeTime; public bool gameIsPaused; //public bool Resumed = false; public static GameManager Instance { get; private set; } private void Awake() { SaveData.Instance.Initialize(); if(Instance != null && Instance != this) { Destroy(gameObject); } else { Instance = this; } SaveScene(); DontDestroyOnLoad(gameObject); SaveData.Instance.LoadSceneData(); SaveData.Instance.LoadMapData(); savePoint = FindObjectOfType<SavePoint>(); } private void Update() { if(Input.GetKeyDown(KeyCode.P)) //test { Debug.Log("P"); SaveData.Instance.SavePlayerData(); } if(Input.GetKeyDown(KeyCode.Escape) && !gameIsPaused) { pauseMenu.FadeUIIn(fadeTime); Time.timeScale = 0; GameManager.Instance.gameIsPaused = true; } if(Input.GetKeyDown(KeyCode.R)) //test { //SaveData.Instance.DeleteAllSaveData(); } } public void SaveGame() { SaveData.Instance.SavePlayerData(); } public void UnpauseGame() { //Resumed = true; Time.timeScale = 1; GameManager.Instance.gameIsPaused = false; //沒有正確銷毀gamemanager 導致需要加GameManager.Instance Debug.Log(gameIsPaused); } public void SaveScene() { //獲取當前場景名稱 string currentSceneName = SceneManager.GetActiveScene().name; SaveData.Instance.sceneName.Add(currentSceneName); SaveData.Instance.SaveSceneData(); //Debug.Log("saved" + currentSceneName); } public void RespawnPlayer() { SaveData.Instance.LoadSavePoint(); if(SaveData.Instance.savePointSceneName != null) //載入重生點的場景 { print(SaveData.Instance.savePointSceneName + "by GameManager"); SceneManager.LoadScene(SaveData.Instance.savePointSceneName); } if(SaveData.Instance.savePointPos != null) //設定重生位置為savePoint { respawnPoint = SaveData.Instance.savePointPos; } else { respawnPoint = platformingRespawnPoint; } PlayerController.Instance.transform.position = respawnPoint; StartCoroutine(UIManager.Instance.DeactiveateDeathScreen()); //重生點淡入淡出 PlayerController.Instance.Respawned(); //使角色重生 } }
SavePoint.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; public class SavePoint : MonoBehaviour { public bool interacted; bool inRange = false; void Update() { if(Input.GetButtonDown("Interact") && inRange ) { interacted = true; SaveData.Instance.savePointSceneName = SceneManager.GetActiveScene().name; SaveData.Instance.savePointPos = new Vector2(gameObject.transform.position.x, gameObject.transform.position.y); GameManager.Instance.platformingRespawnPoint = SaveData.Instance.savePointPos; SaveData.Instance.SavedSavePoint(); SaveData.Instance.SavePlayerData(); SaveData.Instance.SaveMapData(); //SaveData.Instance.SaveSceneData(); Debug.Log("Save by SavePoint.cs"); } } private void OnTriggerEnter2D(Collider2D _collision) { if (_collision.CompareTag("Player")) inRange = true; } private void OnTriggerExit2D(Collider2D _collision) { if (_collision.CompareTag("Player")) { //interacted = false; inRange = false; } } }
August 13, 2024 at 1:38 pm #15579::Hi there I would like to ask if there is a solution to the problem, it has been bothering me for several days but I don’t know how to solve it. I don’t know how to ask you more politely. Please forgive me if I offend you.
August 13, 2024 at 3:06 pm #15580::Apologies for the wait, I have been busy in the meantime.
Would it be alright if i get back to you, sometime within today and tomorrow, with a theory/solution after attempting to work out a solution.
August 13, 2024 at 3:09 pm #15581::Of course, I’m not urging you, I’m just curious if there is a solution. I’m grateful for your help.
August 14, 2024 at 9:24 pm #15588::After going through the code yet again. I’ve come to a conclusion.
The save system for scenes and maps simply does not actually work. The code used to “save” data, is not actually being saved through the method we are using. We’ll have to come up with a functional save system for hashsets since the one we use now only saves 1 value of
sceneName
instead of actually saving the hashset.August 15, 2024 at 11:01 am #15589::I want to know if you have a chance to propose a solution later. I learned most of the programs from you, especially the storage method. This is a type that I have never been exposed to until now. I know nothing about it. , I think I need your help
August 16, 2024 at 12:17 am #15596::MI NI, we can make a video about this, but it will take awhile. Will you be able to wait?
August 16, 2024 at 9:17 am #15597::Of course, thank you for your teaching. It is of great help to me in learning programming.
September 7, 2024 at 6:56 pm #15771::Hi MI NI,
It’s been a while but first, apologies for not revisiting this sooner.
Second, I’ve finally, most probably found the actual issue for why the maps did not work.After revisiting the code again, I’ve determined that the original code does actually work. So let’s just revert the code to this:
In SaveData.cs, we will use the original code where we save both the Maps and the Scenes seperately as hashset strings.
The code here actually does work and is saved in their respective paths.We will not be calling the
SceneData()
orMapData()
from this. So do remove any mentions of it fromInitialize()
.SaveData.cs
public void Initialize() { if (!File.Exists(Application.persistentDataPath + "/save.maps.data")) //if file doesnt exist, well create the file { BinaryWriter writer = new BinaryWriter(File.Create(Application.persistentDataPath + "/save.maps.data")); } if (sceneNames == null) { sceneNames = new HashSet
(); } if (mapNames == null) { mapNames = new HashSet (); } } public void SaveScene() { using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(Application.persistentDataPath + "/save.scenes.data"))) { writer.Write(sceneNames.Count); foreach (string sceneName in sceneNames) { writer.Write(sceneName); } writer.Flush(); } } public void LoadSceneData() { if (File.Exists(Application.persistentDataPath + "/save.scenes.data")) { using (BinaryReader reader = new BinaryReader(File.OpenRead(Application.persistentDataPath + "/save.scenes.data"))) { int sceneCount = reader.ReadInt32(); for (int i = 0; i < sceneCount; i++) { string _sceneName = reader.ReadString(); sceneNames.Add(_sceneName); } } } else { Debug.Log(sceneNames); sceneNames = new HashSet (); } } public void SaveMapData() { using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(Application.persistentDataPath + "/save.maps.data"))) { mapNames = sceneNames; writer.Write(mapNames.Count); foreach (string mapName in mapNames) { writer.Write(mapName); } writer.Flush(); } } public void LoadMapData() { if (File.Exists(Application.persistentDataPath + "/save.maps.data")) { using (BinaryReader reader = new BinaryReader(File.OpenRead(Application.persistentDataPath + "/save.maps.data"))) { int sceneCount = reader.ReadInt32(); for (int i = 0; i < sceneCount; i++) { string _sceneName = reader.ReadString(); mapNames.Add(_sceneName); } } } else { mapNames = new HashSet (); } }
The real issue is in the GameManager.cs.
The GameManager.cs calls
SaveScene()
BEFORE it callsLoadSceneData()
.
Once realizing this, it becomes obvious that this is counter productive.The reason why this is bad is because, everytime you enter a new scene, we will add the scene in the
sceneNames
hashset. That is intented.
However, when we callLoadSceneData()
we are taking all thesceneNames
that were saved throughSaveScene()
.
Because we callSaveScene()
beforeLoadSceneData()
we are never really adding any new scenes and are actually replacing old saved data instead.In other words, we are basically resetting our progress through this. So all we have to do is reorder the code:
GameManager.cs
public static GameManager Instance { get; private set; } private void Awake() { SaveData.Instance.Initialize(); if(Instance != null && Instance != this) { Destroy(gameObject); } else { Instance = this; }
SaveScene();DontDestroyOnLoad(gameObject); SaveData.Instance.LoadSceneData(); SaveScene(); SaveData.Instance.LoadMapData(); savePoint = FindObjectOfType(); } September 9, 2024 at 11:32 am #15793::Hello, I have successfully tested it and it works, but I am facing some problems so that I cannot test and open the map after starting the game. I’ll describe my problem here and I can republish an article if needed.
The problems I’m currently having are:
first question
Pressing ESC immediately when switching scenes will cause the game to freeze permanently.
second question
When I create a new game, ESC, inventory, and maps don’t workSeptember 9, 2024 at 12:34 pm #15794::Could you send your PlayerController.cs and your GameManager.cs?
and maybe your SaveData.cs.September 9, 2024 at 1:10 pm #15795::sure
In addition, I think this problem existed before, not when the storage function was modified this time.
savedata.csusing System.Collections; using System.Collections.Generic; using UnityEngine; using System.IO; using UnityEngine.SceneManagement; [System.Serializable] public struct SaveData { public static SaveData Instance; //map stuff public HashSet
sceneNames; public HashSet mapNames; //savePoint stuff public string savePointSceneName; public Vector2 savePointPos; //player stuff public float playerHealth; public float playerMana; public Vector2 playerPosition; public string lastScene; //player skill public bool playerUnlockWallJump; public bool playerUnlockDash; public bool playeUnlockAirJump; public bool playerUnlockSideSpell; public void Initialize() //初始化 { /* if (!File.Exists(Application.persistentDataPath + "/save.scenes.data")) { BinaryWriter writer = new BinaryWriter(File.Create(Application.persistentDataPath + "/save.scenes.data")); } if (!File.Exists(Application.persistentDataPath + "/save.maps.data")) { BinaryWriter writer = new BinaryWriter(File.Create(Application.persistentDataPath + "/save.maps.data")); } */ if (!File.Exists(Application.persistentDataPath + "/save.maps.data")) //if file doesnt exist, well create the file { BinaryWriter writer = new BinaryWriter(File.Create(Application.persistentDataPath + "/save.maps.data")); } if (sceneNames == null) { sceneNames = new HashSet (); } if (mapNames == null) { mapNames = new HashSet (); } //檢查重生點文件是否存在,否則將建立一個新文件 if (!File.Exists(Application.persistentDataPath + "/save.savePoint.data")) { BinaryWriter writer = new BinaryWriter(File.Create(Application.persistentDataPath + "/save.savePoint.data")); } //檢查玩家文件是否存在,否則將建立一個新文件 if (!File.Exists(Application.persistentDataPath + "/save.player.data")) { BinaryWriter writer = new BinaryWriter(File.Create(Application.persistentDataPath + "/save.player.data")); } } public void SavedSavePoint() { using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(Application.persistentDataPath + "/save.savePoint.data"))) { Debug.Log("SavedSavePoint by SaveData.cs"); writer.Write(savePointSceneName); writer.Write(savePointPos.x); writer.Write(savePointPos.y); } } public void LoadSavePoint() { //if(File.Exists(Application.persistentDataPath + "/save.savePoint.data")) string savePath = Application.persistentDataPath + "/save.savePoint.data"; if(File.Exists(savePath) && new FileInfo(savePath).Length > 0) { using (BinaryReader reader = new BinaryReader(File.OpenRead(Application.persistentDataPath + "/save.savePoint.data"))) { Debug.Log("LoadSavePoint by SaveData.cs"); savePointSceneName = reader.ReadString(); savePointPos.x = reader.ReadSingle(); savePointPos.y = reader.ReadSingle(); } } else { Debug.Log("SavePoint do not exits by SaveData.cs"); } } public void SavePlayerData() //備註:存儲的順序需與讀取的順序相同,否則可能出錯 { using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(Application.persistentDataPath + "/save.player.data"))) { //血量、魔力 playerHealth = PlayerController.Instance.Health; writer.Write(playerHealth); playerMana = PlayerController.Instance.Mana; writer.Write(playerMana); //技能 playerUnlockWallJump = PlayerController.Instance.unlockWallJump; writer.Write(playerUnlockWallJump); playerUnlockDash = PlayerController.Instance.unlockDash; writer.Write(playerUnlockDash); playeUnlockAirJump = PlayerController.Instance.unlockAirJump; writer.Write(playeUnlockAirJump); playerUnlockSideSpell = PlayerController.Instance.unlockSideSpell; writer.Write(playerUnlockSideSpell); //位置 playerPosition = PlayerController.Instance.transform.position; writer.Write(playerPosition.x); writer.Write(playerPosition.y); //場景 lastScene = SceneManager.GetActiveScene().name; writer.Write(lastScene); } } public void LoadPlayerData() { //string savePath = Application.persistentDataPath + "/save.player.data"; //if (File.Exists(savePath) && new FileInfo(savePath).Length > 0) if(File.Exists(Application.persistentDataPath + "/save.player.data")) { using (BinaryReader reader = new BinaryReader(File.OpenRead(Application.persistentDataPath + "/save.player.data"))) { //血量、魔力 playerHealth = reader.ReadSingle(); playerMana = reader.ReadSingle(); //技能 playerUnlockWallJump = reader.ReadBoolean(); playerUnlockDash = reader.ReadBoolean(); playeUnlockAirJump = reader.ReadBoolean(); playerUnlockSideSpell = reader.ReadBoolean(); //位置 playerPosition.x = reader.ReadSingle(); playerPosition.y = reader.ReadSingle(); //場景 lastScene = reader.ReadString(); Debug.Log(lastScene + "LoadPlayerData by SaveData.cs"); SceneManager.LoadScene(lastScene); PlayerController.Instance.transform.position = playerPosition; PlayerController.Instance.Health = playerHealth; PlayerController.Instance.Mana = playerMana; PlayerController.Instance.unlockWallJump = playerUnlockWallJump; PlayerController.Instance.unlockDash = playerUnlockDash; PlayerController.Instance.unlockAirJump = playeUnlockAirJump; PlayerController.Instance.unlockSideSpell = playerUnlockSideSpell; } Debug.Log("load player data"); } else { //如果檔案不存在 Debug.Log("File doesnt exist"); PlayerController.Instance.Health = PlayerController.Instance.maxHealth; PlayerController.Instance.Mana = 0.5f; PlayerController.Instance.unlockWallJump = false; PlayerController.Instance.unlockDash = false; PlayerController.Instance.unlockAirJump = false; PlayerController.Instance.unlockSideSpell = false; } } public void SaveSceneData() { using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(Application.persistentDataPath + "/save.scenes.data"))) { writer.Write(sceneNames.Count); foreach (string sceneName in sceneNames) { writer.Write(sceneName); } writer.Flush(); } } public void LoadSceneData() { if (File.Exists(Application.persistentDataPath + "/save.scenes.data")) { using (BinaryReader reader = new BinaryReader(File.OpenRead(Application.persistentDataPath + "/save.scenes.data"))) { int sceneCount = reader.ReadInt32(); for (int i = 0; i < sceneCount; i++) { string _sceneName = reader.ReadString(); sceneNames.Add(_sceneName); } } } else { Debug.Log(sceneNames); sceneNames = new HashSet (); } } public void SaveMapData() { using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(Application.persistentDataPath + "/save.maps.data"))) { mapNames = sceneNames; writer.Write(mapNames.Count); foreach (string mapName in mapNames) { writer.Write(mapName); } writer.Flush(); } } public void LoadMapData() { if (File.Exists(Application.persistentDataPath + "/save.maps.data")) { using (BinaryReader reader = new BinaryReader(File.OpenRead(Application.persistentDataPath + "/save.maps.data"))) { int sceneCount = reader.ReadInt32(); for (int i = 0; i < sceneCount; i++) { string _sceneName = reader.ReadString(); mapNames.Add(_sceneName); } } } else { mapNames = new HashSet (); } } } GameManager.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; public class GameManager : MonoBehaviour { public string transitionedFromScene; //儲存前一個場景 public Vector2 platformingRespawnPoint; //重生點 public Vector2 respawnPoint; [SerializeField] SavePoint savePoint; [SerializeField] private FadeUI pauseMenu; [SerializeField] private FadeUI mapPause; [SerializeField] private float fadeTime; public bool gameIsPaused; //public bool Resumed = false; bool openMap = false; bool openInventory = false; public static GameManager Instance { get; private set; } private void Awake() { SaveData.Instance.Initialize(); if(Instance != null && Instance != this) { Destroy(gameObject); } else { Instance = this; } DontDestroyOnLoad(gameObject); SaveData.Instance.LoadSceneData(); SaveScene(); SaveData.Instance.LoadMapData(); savePoint = FindObjectOfType<SavePoint>(); } private void Update() { //退出 if (Input.GetKeyDown(KeyCode.Escape) && !gameIsPaused) { pauseMenu.FadeUIIn(fadeTime); Time.timeScale = 0; GameManager.Instance.gameIsPaused = true; } //地圖 if (Input.GetButtonDown("Map") && !openMap && !gameIsPaused) { openMap = true; if (openMap) { Time.timeScale = 0; GameManager.Instance.gameIsPaused = true; } UIManager.Instance.mapHandler.SetActive(true); } else if (Input.GetButtonDown("Map") && openMap) { openMap = false; if (!openMap) { UnpauseGame(); } UIManager.Instance.mapHandler.SetActive(false); } //背包 if (Input.GetButtonDown("Inventory") && !openInventory && !gameIsPaused) { openInventory = true; if(openInventory) { Time.timeScale = 0; GameManager.Instance.gameIsPaused = true; } UIManager.Instance.inventory.SetActive(true); } else if (Input.GetButtonDown("Inventory") && openInventory) { openInventory = false; if(!openInventory) { UnpauseGame(); } UIManager.Instance.inventory.SetActive(false) ; } } public void SaveGame() { SaveData.Instance.SavePlayerData(); } public void UnpauseGame() { //Resumed = true; Time.timeScale = 1; GameManager.Instance.gameIsPaused = false; //沒有正確銷毀gamemanager 導致需要加GameManager.Instance Debug.Log(gameIsPaused); } public void SaveScene() { //獲取當前場景名稱 string currentSceneName = SceneManager.GetActiveScene().name; SaveData.Instance.sceneNames.Add(currentSceneName); SaveData.Instance.SaveSceneData(); //Debug.Log("saved" + currentSceneName); } public void RespawnPlayer() { SaveData.Instance.LoadSavePoint(); if(SaveData.Instance.savePointSceneName != null) //載入重生點的場景 { print(SaveData.Instance.savePointSceneName + "by GameManager"); SceneManager.LoadScene(SaveData.Instance.savePointSceneName); } if(SaveData.Instance.savePointPos != null) //設定重生位置為savePoint { respawnPoint = SaveData.Instance.savePointPos; } else { respawnPoint = platformingRespawnPoint; } PlayerController.Instance.transform.position = respawnPoint; StartCoroutine(UIManager.Instance.DeactiveateDeathScreen()); //重生點淡入淡出 PlayerController.Instance.Respawned(); //使角色重生 } /* public void ToggleMap() { if (openMap) { UIManager.Instance.mapHandler.SetActive(true); } else { UIManager.Instance.mapHandler.SetActive(false); } } */ }
September 10, 2024 at 12:43 pm #15808::1. For your Pause menu freezing the game, the only thing you need to do is to ensure your resume game is called. In other words, making sure you can press the resume button.
Thus, let’s first see why your button isn’t able to be pressed. For this, I’m not too sure, however can you check out point 2b. of this article, turning off the raycast targetting of the “Scene Fader”:
How to fix an unclickable Button in Unity’s Canvas UI system
This is because it’s the only game object in the scene that could possibly be blocking the pause menu.
Furthermore, I suggest you allow pressing the escape button again to unpause the game anyways.
2. For your Pause, Map and Inventory not appearing. This is because you put all three into the GameManager.cs. The problem with that is due to the fact that the code we used for loading the game’s map, scenes and boss data is all not fully correct.
Whenever we load the game’s data, we search for whether their file paths exists. but we forgot to check if there’s anything inside the file. Because of this, we will always be returned with an error saying that there was no data to be retrieved from the filepaths.
Whenever your code encounters an error, the script will be paused there. Thus, since we called a lot of Load Data methods in the GameManager.csAwake()
method, our GameManager.cs encountered errors when we reset the game’s data and stopped functioning for theUpdate()
method to fire.
Thereby causing your map, inventory and pause menu unable to open.The fix is pretty simple, we just need to add the line that was commented out in your
LoadPlayerData()
, into each of the Load methods:GameManager.cs
public void LoadPlayerData() {
//string savePath = Application.persistentDataPath + "/save.player.data";//if (File.Exists(savePath) && new FileInfo(savePath).Length > 0)if(File.Exists(Application.persistentDataPath + "/save.player.data")){ using (BinaryReader reader = new BinaryReader(File.OpenRead(Application.persistentDataPath + "/save.player.data"))) { .... } Debug.Log("load player data"); } else { .... } } public void LoadSceneData() { if (File.Exists(Application.persistentDataPath + "/save.scenes.data") && new FileInfo(Application.persistentDataPath + "/save.scenes.data").Length > 0)) { using (BinaryReader reader = new BinaryReader(File.OpenRead(Application.persistentDataPath + "/save.scenes.data"))) { ... } } else {Debug.Log(sceneNames);Debug.Log("File doesnt exist"); sceneNames = new HashSet(); } } public void LoadMapData() { if (File.Exists(Application.persistentDataPath + "/save.maps.data") && new FileInfo(Application.persistentDataPath + "/save.maps.data").Length > 0)) { using (BinaryReader reader = new BinaryReader(File.OpenRead(Application.persistentDataPath + "/save.maps.data"))) { ... } } else { Debug.Log("File doesnt exist"); mapNames = new HashSet(); } }What this does is it checks for the contents of each file path first and sees if there is anything inside. If there is nothing inside, then we fire the else statement that the file doesnt exist. The reason we have to do this is because of our SaveData.cs
Initialize()
creating the file paths even if we deleted them with the reset data.has upvoted this post. September 12, 2024 at 12:28 pm #15814::Hello, I’m sorry for the late reply. After I started Unity today and made some modifications, I still can’t use ESC, map and inventory when starting a new game. In addition, after I set ESC to be the same button to switch the pause interface on and off, the freezing problem seems to be there. Got resolved (this needs to be confirmed as I have bigger issues). The bigger problem is that my pause interface and inventory are no longer usable. I haven’t made any modifications during this period, but suddenly all the buttons are invalid. I refer to your article on how to fix unclickable Button. , but it seems to have no effect
After testing, I found that the UI Button cannot be triggered on the first map, but it can be triggered on the second map. I will add a test video below. This makes me confused. If you need any information or other, please must tell me
Gamemanager.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; public class GameManager : MonoBehaviour { public string transitionedFromScene; //儲存前一個場景 public Vector2 platformingRespawnPoint; //重生點 public Vector2 respawnPoint; [SerializeField] SavePoint savePoint; [SerializeField] private FadeUI pauseMenu; [SerializeField] private FadeUI mapPause; [SerializeField] private float fadeTime; public bool gameIsPaused; //public bool Resumed = false; bool openMap = false; bool openInventory = false; public static GameManager Instance { get; private set; } private void Awake() { SaveData.Instance.Initialize(); if(Instance != null && Instance != this) { Destroy(gameObject); } else { Instance = this; } DontDestroyOnLoad(gameObject); SaveData.Instance.LoadSceneData(); SaveScene(); SaveData.Instance.LoadMapData(); savePoint = FindObjectOfType<SavePoint>(); } private void Update() { //退出 if (Input.GetKeyDown(KeyCode.Escape) && !gameIsPaused) { pauseMenu.FadeUIIn(fadeTime); Time.timeScale = 0; GameManager.Instance.gameIsPaused = true; } else if(Input.GetKeyDown(KeyCode.Escape) && gameIsPaused) { UnpauseGame(); pauseMenu.FadeUIOut(fadeTime); } //地圖 if (Input.GetButtonDown("Map") && !openMap && !gameIsPaused) { openMap = true; if (openMap) { Time.timeScale = 0; GameManager.Instance.gameIsPaused = true; } UIManager.Instance.mapHandler.SetActive(true); } else if (Input.GetButtonDown("Map") && openMap) { openMap = false; if (!openMap) { UnpauseGame(); } UIManager.Instance.mapHandler.SetActive(false); } //背包 if (Input.GetButtonDown("Inventory") && !openInventory && !gameIsPaused) { openInventory = true; if(openInventory) { Time.timeScale = 0; GameManager.Instance.gameIsPaused = true; } UIManager.Instance.inventory.SetActive(true); } else if (Input.GetButtonDown("Inventory") && openInventory) { openInventory = false; if(!openInventory) { UnpauseGame(); } UIManager.Instance.inventory.SetActive(false) ; } } public void SaveGame() { SaveData.Instance.SavePlayerData(); } public void UnpauseGame() { //Resumed = true; Time.timeScale = 1; GameManager.Instance.gameIsPaused = false; //沒有正確銷毀gamemanager 導致需要加GameManager.Instance Debug.Log(gameIsPaused); } public void SaveScene() { //獲取當前場景名稱 string currentSceneName = SceneManager.GetActiveScene().name; SaveData.Instance.sceneNames.Add(currentSceneName); SaveData.Instance.SaveSceneData(); //Debug.Log("saved" + currentSceneName); } public void RespawnPlayer() { SaveData.Instance.LoadSavePoint(); if(SaveData.Instance.savePointSceneName != null) //載入重生點的場景 { print(SaveData.Instance.savePointSceneName + "by GameManager"); SceneManager.LoadScene(SaveData.Instance.savePointSceneName); } if(SaveData.Instance.savePointPos != null) //設定重生位置為savePoint { respawnPoint = SaveData.Instance.savePointPos; } else { respawnPoint = platformingRespawnPoint; } PlayerController.Instance.transform.position = respawnPoint; StartCoroutine(UIManager.Instance.DeactiveateDeathScreen()); //重生點淡入淡出 PlayerController.Instance.Respawned(); //使角色重生 } /* public void ToggleMap() { if (openMap) { UIManager.Instance.mapHandler.SetActive(true); } else { UIManager.Instance.mapHandler.SetActive(false); } } */ }
SavaData.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; using System.IO; using UnityEngine.SceneManagement; [System.Serializable] public struct SaveData { public static SaveData Instance; //map stuff public HashSet<string> sceneNames; public HashSet<string> mapNames; //savePoint stuff public string savePointSceneName; public Vector2 savePointPos; //player stuff public float playerHealth; public float playerMana; public Vector2 playerPosition; public string lastScene; //player skill public bool playerUnlockWallJump; public bool playerUnlockDash; public bool playeUnlockAirJump; public bool playerUnlockSideSpell; public void Initialize() //初始化 { if (!File.Exists(Application.persistentDataPath + "/save.maps.data")) //if file doesnt exist, well create the file { BinaryWriter writer = new BinaryWriter(File.Create(Application.persistentDataPath + "/save.maps.data")); } if (sceneNames == null) { sceneNames = new HashSet<string>(); } if (mapNames == null) { mapNames = new HashSet<string>(); } //檢查重生點文件是否存在,否則將建立一個新文件 if (!File.Exists(Application.persistentDataPath + "/save.savePoint.data")) { BinaryWriter writer = new BinaryWriter(File.Create(Application.persistentDataPath + "/save.savePoint.data")); } //檢查玩家文件是否存在,否則將建立一個新文件 if (!File.Exists(Application.persistentDataPath + "/save.player.data")) { BinaryWriter writer = new BinaryWriter(File.Create(Application.persistentDataPath + "/save.player.data")); } } public void SavedSavePoint() { using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(Application.persistentDataPath + "/save.savePoint.data"))) { Debug.Log("SavedSavePoint by SaveData.cs"); writer.Write(savePointSceneName); writer.Write(savePointPos.x); writer.Write(savePointPos.y); } } public void LoadSavePoint() { //if(File.Exists(Application.persistentDataPath + "/save.savePoint.data")) string savePath = Application.persistentDataPath + "/save.savePoint.data"; if(File.Exists(savePath) && new FileInfo(savePath).Length > 0) { using (BinaryReader reader = new BinaryReader(File.OpenRead(Application.persistentDataPath + "/save.savePoint.data"))) { Debug.Log("LoadSavePoint by SaveData.cs"); savePointSceneName = reader.ReadString(); savePointPos.x = reader.ReadSingle(); savePointPos.y = reader.ReadSingle(); } } else { Debug.Log("SavePoint do not exits by SaveData.cs"); } } public void SavePlayerData() //備註:存儲的順序需與讀取的順序相同,否則可能出錯 { using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(Application.persistentDataPath + "/save.player.data"))) { //血量、魔力 playerHealth = PlayerController.Instance.Health; writer.Write(playerHealth); playerMana = PlayerController.Instance.Mana; writer.Write(playerMana); //技能 playerUnlockWallJump = PlayerController.Instance.unlockWallJump; writer.Write(playerUnlockWallJump); playerUnlockDash = PlayerController.Instance.unlockDash; writer.Write(playerUnlockDash); playeUnlockAirJump = PlayerController.Instance.unlockAirJump; writer.Write(playeUnlockAirJump); playerUnlockSideSpell = PlayerController.Instance.unlockSideSpell; writer.Write(playerUnlockSideSpell); //位置 playerPosition = PlayerController.Instance.transform.position; writer.Write(playerPosition.x); writer.Write(playerPosition.y); //場景 lastScene = SceneManager.GetActiveScene().name; writer.Write(lastScene); } } public void LoadPlayerData() { string savePath = Application.persistentDataPath + "/save.player.data"; if (File.Exists(savePath) && new FileInfo(savePath).Length > 0) //if(File.Exists(Application.persistentDataPath + "/save.player.data")) { using (BinaryReader reader = new BinaryReader(File.OpenRead(Application.persistentDataPath + "/save.player.data"))) { //血量、魔力 playerHealth = reader.ReadSingle(); playerMana = reader.ReadSingle(); //技能 playerUnlockWallJump = reader.ReadBoolean(); playerUnlockDash = reader.ReadBoolean(); playeUnlockAirJump = reader.ReadBoolean(); playerUnlockSideSpell = reader.ReadBoolean(); //位置 playerPosition.x = reader.ReadSingle(); playerPosition.y = reader.ReadSingle(); //場景 lastScene = reader.ReadString(); Debug.Log(lastScene + "LoadPlayerData by SaveData.cs"); SceneManager.LoadScene(lastScene); PlayerController.Instance.transform.position = playerPosition; PlayerController.Instance.Health = playerHealth; PlayerController.Instance.Mana = playerMana; PlayerController.Instance.unlockWallJump = playerUnlockWallJump; PlayerController.Instance.unlockDash = playerUnlockDash; PlayerController.Instance.unlockAirJump = playeUnlockAirJump; PlayerController.Instance.unlockSideSpell = playerUnlockSideSpell; } Debug.Log("load player data"); } else { //如果檔案不存在 Debug.Log("File doesnt exist"); PlayerController.Instance.Health = PlayerController.Instance.maxHealth; PlayerController.Instance.Mana = 0.5f; PlayerController.Instance.unlockWallJump = false; PlayerController.Instance.unlockDash = false; PlayerController.Instance.unlockAirJump = false; PlayerController.Instance.unlockSideSpell = false; } } public void SaveSceneData() { using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(Application.persistentDataPath + "/save.scenes.data"))) { writer.Write(sceneNames.Count); foreach (string sceneName in sceneNames) { writer.Write(sceneName); } writer.Flush(); } } public void LoadSceneData() { if (File.Exists(Application.persistentDataPath + "/save.scenes.data")) { using (BinaryReader reader = new BinaryReader(File.OpenRead(Application.persistentDataPath + "/save.scenes.data"))) { int sceneCount = reader.ReadInt32(); for (int i = 0; i < sceneCount; i++) { string _sceneName = reader.ReadString(); sceneNames.Add(_sceneName); } } } else { Debug.Log("File doesnt exist"); sceneNames = new HashSet<string>(); } } public void SaveMapData() { using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(Application.persistentDataPath + "/save.maps.data"))) { mapNames = sceneNames; writer.Write(mapNames.Count); foreach (string mapName in mapNames) { writer.Write(mapName); } writer.Flush(); } } public void LoadMapData() { if (File.Exists(Application.persistentDataPath + "/save.maps.data")) { using (BinaryReader reader = new BinaryReader(File.OpenRead(Application.persistentDataPath + "/save.maps.data"))) { int sceneCount = reader.ReadInt32(); for (int i = 0; i < sceneCount; i++) { string _sceneName = reader.ReadString(); mapNames.Add(_sceneName); } } } else { Debug.Log("File doesnt exist"); mapNames = new HashSet<string>(); } } }
September 12, 2024 at 12:34 pm #15815::Could you try applying the changes [the addition of the file.length check] to SaveData.cs
LoadSceneData()
andLoadMapData()
like in my post above?public void LoadSceneData() { if (File.Exists(Application.persistentDataPath + "/save.scenes.data") && new FileInfo(Application.persistentDataPath + "/save.scenes.data").Length > 0)) public void LoadMapData() { if (File.Exists(Application.persistentDataPath + "/save.maps.data") && new FileInfo(Application.persistentDataPath + "/save.maps.data").Length > 0))
-
AuthorPosts
- You must be logged in to reply to this topic.
Advertisement below: