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 3 months, 2 weeks ago by MI NI.
-
AuthorPosts
-
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.August 8, 2024 at 2:33 pm #15538::First. Change your MapManager.cs code to this:
private void OnEnable() { SaveData.Instance.LoadMapData(); UpdateMap(); }
This should make your maps load properly on start of the game and when you activate a save point.
next
Can you send your SaveData.cs code again? I suspect you forgot to delete some items off from the script that is retaining
mapName
information.I’ve tested out the method and overall it is able to save and delete just fine otherwise.
August 8, 2024 at 3:23 pm #15539::Okay, sorry to trouble you.
Regarding the first question, I think my initial idea was wrong, which caused you to misunderstand my idea. Regarding this point, I am very concerned about the construction. I think I want to be like Hollow Knight, and only update when interacting with Bench. Map, if according to the method you provided, the map will be updated every time “Map” is pressed, which may not be what I want. But this puts me in a situation where if I restart the game, I cannot update the map to the current progress before interacting with Bench.
SaveData.cs
<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; 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.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>(); } } } </code>
August 8, 2024 at 3:51 pm #15540::Actually, i believe it’s the opposite. I am actually making it such that your map only updates after interacting with Bench.
The reason as to how my method above works is through these steps:
- The MapManager calls to
UpdateMap()
. UpdateMap()
will only work whenmapName
in SaveData.cs has any value.mapName
will only ever be updated afterSaveMapData()
is called through the Bench/SavePoint.cs
Thus, ONLY whenever you interact with a bench, you update
mapName
which thereby updates the maps itself. And with the update method being outside of checking for bench interaction, it means that if you continue a game after exiting, it will still update to the last time you saved progress.So long as
SaveMapData()
is not called anywhere else but the bench before.
Apart from that, you should change your
Initialize()
method as I believe that’s part of the reason for the issues you may face with deleting the files. Or it’s worth a shot in any case://檢查場景文件是否存在,否則將建立一個新文件 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")); }August 8, 2024 at 4:27 pm #15541::I think I may have encountered too many problems. For the problems that still exist after I made the above changes, I recorded a video to demonstrate the problems I encountered.
- After I interact with any Bench, I can directly update the map as long as I enter the map without interacting with the Bench of the map.
- After creating a new game, it will be normal to open the map at the beginning, but after interacting with Bench, the last data will be restored.
- After I created a new game, I could not call the pause menu again. Although I could not see my keyboard, at the end of the video, I tried to press the ECS key, but it would not respond.
MapManager.cs
<code>private void OnEnable() { savePoint = FindObjectOfType<SavePoint>(); SaveData.Instance.LoadMapData(); UpdateMap(); }</code>
August 9, 2024 at 5:03 pm #15546::Okay, I’m going to need you to send me the following scripts:
MapManager.cs
SaveData.cs
GameManager.cs
SavePoint.cs
Afterwards, i’ll take a look at your code and get back to you on what went wrong.
- Remove calling for
-
AuthorPosts
- You must be logged in to reply to this topic.
Advertisement below: