Get 10% off orders above 50% with SEPT2025.
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 1 year ago by
MI NI.
-
AuthorPosts
-
August 5, 2024 at 1:28 am #15492August 5, 2024 at 1:35 am #15493::
Your scene data is resetting everytime you enter a scene. May i affirm that in your scene, you do not have a game object that you placed the SaveData script onto right?
August 5, 2024 at 10:16 am #15495::I checked all my game objects and made sure none placed SaveData.cs But I would like to ask, when there are a large number of game objects, is there a way to know which objects use this script?
August 5, 2024 at 10:20 am #15496::In the Scene Hierarchy search bar you can use “t:” followed by the name of the component you are looking for to see all objects that contain said component.
For instance you can use: “t:button” to find all objects that contain a button component, “t:boxcollider2d” to find all box collider 2d’s in the scene. “t:gamemanager” to find all objects with the GameManager script. or “t:savedata” to find savedata scripts.
August 5, 2024 at 10:30 am #15497::Thanks for your tutorial, I used t:SaveData and double-checked that I did not place SaveData.cs in any game object
August 5, 2024 at 2:23 pm #15500::MI NI, can you try changing the
SaveData
object to be aclass
instead of astruct
. See if it fixes the issue.August 5, 2024 at 3:04 pm #15501August 5, 2024 at 5:49 pm #15502::After looking through your project i’ve found the issue.
Disappointingly, It had slipped my mind to not realize that your code was slightly different from ours. It’s the inclusion of this piece of code:
public void Initialize() //ªì©l¤Æ { 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 } } LoadSceneData(); } public void SaveSceneData() { using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(Application.persistentDataPath + "/save.scenes.data"))) { 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>(); } }
The thing is, we did not actually implement a way to save the scene names like we do player data and i had also forgotten to add that in for the series. So these 2 methods were unfamiliar yet i thought they were normal.
In any case, what the issue is, your
LoadSceneData()
is being called inInitialize
. The issue with that is the fact that your GameManager.cs calls your SaveData.csInitialize()
method inAwake()
.Thus every scene you enter, your SaveData.cs will call
LoadSceneData()
.The real problem comes due to the fact that you have no way of calling
SaveSceneData()
. Meaning, that yoursceneNames
data, that you load throughLoadSceneData()
every time you enter a scene, is empty. Thereby causing yoursceneNames
to be null everytime you enter a new scene and thus causing your maps to never progress.
If you want to keep your methods, since they will be good in saving your data, you should just remove that one call for
LoadSceneData()
inInitialize()
, I marked it above, and also look towards callingSaveSceneData()
andLoadSceneData()
somewhere else more appropriate, like in yourSavePlayerData()
.August 5, 2024 at 9:08 pm #15503::After modifying the LoadSceneData();, it worked, but I found that after restarting the game, the map resets. I tried moving SaveSceneData() and LoadSceneData() into SavePlayerData() but it doesn’t work. I want to know how I should modify it to be successful.
<code>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; //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 } //LoadSceneData(); } //檢查重生點文件是否存在,否則將建立一個新文件 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>(); } } 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); //地圖TEST writer.Write(sceneName.Count); foreach (string sceneName in sceneName) { writer.Write(sceneName); } } } 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"); //地圖TEST int sceneCount = reader.ReadInt32(); sceneName = new HashSet<string>(); for (int i = 0; i < sceneCount; i++) { string _sceneName = reader.ReadString(); sceneName.Add(_sceneName); } 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; //地圖TEST sceneName = new HashSet<string>(); } } /* public void SaveSceneData() { using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(Application.persistentDataPath + "/save.scenes.data"))) { 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 ResetSavePoint() { savePointSceneName = null; savePointPos = Vector2.zero; } public void ResetPlayerData() { playerHealth = PlayerController.Instance.maxHealth; playerMana = 0; lastScene = null; playerUnlockWallJump = false; playerUnlockDash = false; playeUnlockAirJump = false; playerUnlockSideSpell = false; } public void ResetSceneData() { sceneName.Clear(); } public void DeleteScenesData()//刪除資料 { string path = Application.persistentDataPath + "/save.scenes.data"; if (File.Exists(path)) { File.Delete(path); Debug.Log("Scenes data deleted."); } ResetSceneData(); } public void DeletePlayerData()//刪除資料 { string path = Application.persistentDataPath + "/save.player.data"; if (File.Exists(path)) { File.Delete(path); Debug.Log("Player save data deleted."); } ResetPlayerData(); } public void DeleteSavePointData()//刪除資料 { string path = Application.persistentDataPath + "/save.savePoint.data"; if (File.Exists(path)) { File.Delete(path); Debug.Log("SavePoint save data deleted."); } ResetSavePoint(); } public void DeleteAllSaveData() { DeleteScenesData(); DeleteSavePointData(); DeletePlayerData(); } */ } </code>
August 5, 2024 at 9:55 pm #15504::If you take a look at your code again, your
LoadSceneData()
method code is wrong.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>(); } }That line that you moved into
LoadPlayerData()
is a problem because what you are doing is resetting all saved maps every time you want to load them.August 5, 2024 at 11:41 pm #15505::I don’t know how to mark the text with a green background or a red background in the code, I use //NEW and //Delete instead
I tried making changes but it didn’t work, I was actually trying to move the
SaveSceneData()
andLoadSceneData()
routines intoSavePlayerData()
andLoadPlayerData()
. But just in case I still tested the modifications you told me, and also I found that mySaveSceneData()
was not called and I tried to add it to the interaction of myBench.cs
but also doesn’t work<code>public struct SaveData { public static SaveData Instance; //map stuff public HashSet<string> sceneName; //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 } //NEW LoadSceneData(); } //檢查重生點文件是否存在,否則將建立一個新文件 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>(); } } 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); //NEW /* //地圖 writer.Write(sceneName.Count); foreach (string sceneName in sceneName) { writer.Write(sceneName); } */ } } 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"); //NEW /* //地圖 int sceneCount = reader.ReadInt32(); //sceneName = new HashSet<string>(); for (int i = 0; i < sceneCount; i++) { string _sceneName = reader.ReadString(); sceneName.Add(_sceneName); } */ 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; //NEW /* //地圖 sceneName = new HashSet<string>(); */ } } //Delete 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>(); } }</code>
<code>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(); //NEW 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; } } }</code>
August 6, 2024 at 12:24 am #15506::Okay, can you send a video now of how it looks now in the game?
I’m assuming you travel through the scenes and overall the map works. However upon saving and leaving then reopening the game, your map progress was not properly saved? If so, then after you reopen, try saving at the save point again then open up the map again. I presume you will see your progress has returned.
If this is the case, the only issue regarding this is that your map only updates when it is opened, and when the bench has been interacted with. But upon starting the game the map starts with no maps progressed except stage 1.
I would recommend you can try to make a way to update the map on start in some way [which can only be done when the map is active which it isnt by default]. Otherwise, give me some time to make a solution to it if this is the issue.
If this isn’t the issue, i’ll tell you my new set of thoughts depending on the video.
also as for how we handle text. right now you use the
'
tiddle as your way of marking code. in actuality we use the open and close bracketted arrows for codes:<pre> code </pre>
One advantage for using
'
for code is that you can type out<>
. while using<pre> and </pre>
will allow the code to automatically be boxed up and have the capability to be highlighted.as for marking code yellow:
<mark> code </mark>
green:<mark class="green"> code </mark>
red:<del> code </del>
August 6, 2024 at 12:50 am #15507::I discovered several issues after recording the video. Whether it is restarting Unity or returning to the main menu of the game to continue the game, My map will only have stage_1 after restarting. However, the saved map will be restored after interacting with Bench again.
In addition, if you restart a new game and interact with Bench, the map saved in the previous game will be restored. This seems to mean that I did not successfully call the map data when continuing the game. And the map data was not deleted when restarting the game.
I commented out the program I used to integrate the data into SavePlayerData in advance and marked it as //NEW MAP DATA
<code>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; //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 } LoadSceneData(); } //檢查重生點文件是否存在,否則將建立一個新文件 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>(); } } 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); /* //NEW MAP DATA writer.Write(sceneName.Count); foreach (string sceneName in sceneName) { writer.Write(sceneName); } */ } } 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"); /* //NEW MAP DATA int sceneCount = reader.ReadInt32(); //sceneName = new HashSet<string>(); for (int i = 0; i < sceneCount; i++) { string _sceneName = reader.ReadString(); sceneName.Add(_sceneName); } */ 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; /* //NEW MAP DATA sceneName = new HashSet<string>(); */ } } 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>(); } } } </code>
August 6, 2024 at 3:13 pm #15508::As I had already explained above:
If this is the case, the only issue regarding this is that your map only updates when it is opened, and when the bench has been interacted with. But upon starting the game the map starts with no maps progressed except stage 1.
I would recommend you can try to make a way to update the map on start in some way [which can only be done when the map is active which it isnt by default]
I can make you a suggestion to create a duplicate hashset similar to
sceneNames
in SaveData.cs, as well as a duplicateLoadSceneData()
&SaveSceneData()
for this new hashset.Then instead of using the same
SaveSceneData()
, inside the duplicate method, change the code to set your duplicate hashset tosceneNames
value.You should call the duplicate save method inside your Bench script when you interact with it.
Then in your GameManager.cs, call
SaveSceneData()
insideSaveScene()
instead of calling it from the bench script.Then, you can call your duplicate load method inside MapManager.cs
OnEnable()
, before calllingUpdateMap()
without the need of checking for the bench interaction. Finally swap outsceneNames
in theUpdateMap()
method with your duplicate hashset.
Doing so should help make your map manager check your scene data instead of checking your bench interaction to update your map. Furthermore, you wont be taking the constantly updating
sceneNames
data but what you actually saved instead.Furthermore, should you close the game, all unupdated maps will be saved in
sceneNames
through the gamemanager callingSaveSceneData()
constantly.August 6, 2024 at 6:09 pm #15511::I’m sorry for my stupidity, maybe I’m not sure what you mean due to translation. I tried adding (mark) in (pre)(/pre) but I don’t know if this is how to use it
I created a new Hashset named mapName and created duplicate LoadSceneData() and SaveSceneData() . I changed it to Load and SaveMapData().
But I don’t quite understand. Then instead of using the same SaveSceneData(), inside the duplicate method, change the code to set your duplicate hashset to sceneNames value. How to do this
//map stuff public HashSet<string> sceneName; public HashSet[string] mapName; ..... 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 } LoadSceneData(); } //檢查場景文件是否存在,否則將建立一個新文件 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 } LoadSceneData(); } //檢查重生點文件是否存在,否則將建立一個新文件 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 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"); 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); } } } else { mapName = new HashSet[string](); } }
August 7, 2024 at 9:06 pm #15514::No, you used the marks correctly, it’s just the post that didn’t load your message correctly.
Sorry for the unclear instructions. But here’s how you should change your code for each script first:
SaveData.cs
First We’ll stop loading the scene data since it will keep resetting the data incorrectly. We’ll instead call it somewhere else.
Next we’ll have to make our
mapName
by taking the same value assceneName
.In this case,
mapName
will be called by our MapManager.cs to update the map. WhereassceneName
is only used to retain the information of scenes that we’ve been through.- Remove calling for
LoadSceneData()
inInitialize()
- In
SaveMapData()
, setmapName
tosceneName
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 }
LoadSceneData();} //檢查場景文件是否存在,否則將建立一個新文件 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 }LoadSceneData();} ... } 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); } } }
MapManager.cs
Make sure that
mapName
is used inUpdateMap()
.- In
UpdateMap()
change the load ofsceneName
tomapName
instead
public void UpdateMap() {
var savedScenes = SaveData.Instance.sceneName;var savedScenes = SaveData.Instance.mapName; for(int i = 0; i < maps.Length; i++) { if(savedScenes.Contains("Cave_" + (i + 1))) //this is i + 1 as arrays start from 0 { maps[i].SetActive(true); } else { maps[i].SetActive(false); } } }
GameManager.cs
We also have to make sure to save all our visited scene data somehow, which we’ll do so by calling
SaveSceneData()
through the same method we used to save the scenes,SaveScene()
.Then also make sure that we’ve loaded the saved information whenever we open the game by calling our load methods in the
Awake()
function.- Call
LoadMapData()
andLoadSceneData()
inAwake()
- In
SaveScene()
, callSaveSceneData()
private void Awake() { .... SaveScene(); DontDestroyOnLoad(gameObject); SaveData.Instance.LoadSceneData(); SaveData.Instance.LoadMapData(); } public void SaveScene() { string currentSceneName = SceneManager.GetActiveScene().name; SaveData.Instance.sceneNames.Add(currentSceneName); SaveData.Instance.SaveSceneData(); }
SavePoint.cs
Finally, we want to update our
mapName
by callingSaveMapData()
, which we’ll do so through the Bench/SavePoint since that’s how they will be updated.- Call
SaveMapData()
inUpdate()
void Update() { if (Input.GetButtonDown("Interact") && inRange) { interacted = true; SaveData.Instance.benchSceneName = SceneManager.GetActiveScene().name; SaveData.Instance.benchPos = new Vector2(gameObject.transform.position.x, gameObject.transform.position.y); SaveData.Instance.SaveBench(); SaveData.Instance.SavePlayerData(); SaveData.Instance.SaveMapData(); } }
With that, this should be all you need to save and load your map data.
August 7, 2024 at 11:03 pm #15515::The post doesn’t seem to be loading my messages correctly again, I’m not sure if I should remove those tags so you can view them
After I made the above modifications, it was still the same as before, but I tried to find the error point. I found that the <per>mapsName</per> was actually stored after entering the game, so I couldn’t find the error. I finally printed the error in <per>UpdateMap()</per> <per>maps[i].SetActive(true&false);</per>, I found that when entering the game and pressing to open the map, <per>UpdateMap()</per> will not be loaded. It will only be loaded after interacting with the storage point and pressing to open the map. This is weird, what do you think?
<per>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))); } } }</per>
August 7, 2024 at 11:31 pm #15516::I think I found the problem. In MapManager, OnEnable() will only execute UpdateMap() after interacting with Bench.cs; I’m not sure if I should keep this code and would like to know what you think. In addition, when I create a new game, the maps data cannot be deleted correctly, but I don’t know what went wrong.
Update Post, I found that moving UpdateMap() outside will cause it to go to any stage, and there will be no need to find the save point to update the map, so my idea is to declare UpdateMap() as public, and in Execute UpdateMap() once in PlayerController’s Awake(). I would like to know if there is a better way to try.
<per>private void OnEnable() { savePoint = FindObjectOfType<SavePoint>(); <mark class=”green”> UpdateMap();
/ if (savePoint != null) { if(savePoint.interacted) { UpdateMap(); } } /}</per><per>public class MenuSaveData : MonoBehaviour { public void ResetSaveData() { string path = Application.persistentDataPath;
// Delete all save files if they exist string[] saveFiles = { path + "/save.savePoint.data", path + "/save.player.data", path + "/save.scenes.data", path + "/save.maps.data" //path + "/save.shade.data" }; foreach (string saveFile in saveFiles) { try { if (File.Exists(saveFile)) { File.Delete(saveFile); Debug.Log(saveFile + " deleted."); } } catch (System.Exception ex) { Debug.LogError("Failed to delete " + saveFile + ": " + ex.Message); } } // Ensure SaveData is initialized SaveData.Instance.Initialize(); //SaveData.Instance.DeleteAllSaveData(); // Forcefully set the tutorial scene SaveData.Instance.lastScene = new string("Stage_1"); Debug.Log("All save data has been reset."); }</per>
August 8, 2024 at 10:55 am #15533::When you are using the code blocks, you can still use
'
instead of<pre>
I do not see your issue with the
mapName
, in the sense that i don’t believe you’ve described what is going on with it that is a problem. Could you show a video with how themapName
fails to be deleted or load correctly on start?Regarding your proposed fix. The reason for
UpdateMap()
to be called inOnEnable()
only after interacting with the save point is because we are following Hollow Knight in the tutorial.To be clear, the mechanic is supposed to work the way it does as you experienced. Which is that the map will only update once you save the game at a save point.
However, you can change it to fit the needs of your game. Which also means that your change is okay.
August 8, 2024 at 11:38 am #15535::This is my video. In the video I try to print out the saved content while executing
LoadMapData()
. When I re-entered Stage 2, Stage 1 and Stage 2 were indeed printed out, but I still needed to interact with Bench again to restore the saved map data.It also demonstrated that I could not delete the data correctly when creating a new game. - Remove calling for
-
AuthorPosts
- You must be logged in to reply to this topic.