Forum begins after the advertisement:
[Part 8] How to let each health and mana orbs call once only in the game
Home › Forums › Video Game Tutorial Series › Creating a Metroidvania in Unity › [Part 8] How to let each health and mana orbs call once only in the game
- This topic has 45 replies, 2 voices, and was last updated 6 months, 2 weeks ago by Elvin Sim.
-
AuthorPosts
-
June 7, 2024 at 12:19 am #15021June 7, 2024 at 12:50 am #15024::
Okay so what i meant was for the Pickupmanager.cs.
What you want it to do is for it to always call for It’s own
LoadAndDeactivateInteractedObjects()
method everytime you enter a new scene. But the issue was i did not account forStart()
function not doing so normally.What I mean by that is that, the code in
Awake()
is always called after entering a scene, thus it can be called multiple times by a singleton because that’s the start of a new process for your scripts, calling them awake. WhereasStart()
is only it’s initial initialization. Meaning, the first time it ever appears, it will only do it’sStart()
method once and never again.Thus to solve this issue, just move your code from
Start()
toAwake()
.public class PickupManager : MonoBehaviour { public static PickupManager Instance; private void Awake() { if(Instance != null && Instance != this) { Destroy(gameObject); } else { Instance = this; } DontDestroyOnLoad(gameObject); LoadAndDeactivateInteractedObjects(); // Load saved data and deactivate pickups }
// Start is called before the first frame update void Start() { LoadAndDeactivateInteractedObjects(); // Load saved data and deactivate pickups }June 7, 2024 at 3:18 am #15025June 7, 2024 at 3:20 am #15026::As you can see for the first video the system works, After I pickup the orbs, and go to main menu and load the game again, it is ok, but when I press the new game, the orbs disapeared. For the Second video is that I exit and run again the unity, and go to load game (previous data(first video)), the orbs appeared again.
June 7, 2024 at 3:21 am #15027::<code>[System.Serializable] public struct SaveData { public static SaveData Instance; //map stuff public HashSet<string> sceneNames; //bench stuff public string benchSceneName; public Vector2 benchPos; //player stuff public int playerHealth; public int playerMaxHealth; public int playerHeartShards; public float playerMana; public int playerManaOrbs; public int playerOrbShard; public float playerOrb0fill, playerOrb1fill, playerOrb2fill; public bool playerHalfMana; public Vector2 playerPosition; public string lastScene; public bool playerUnlockedWallJump, playerUnlockedDash, playerUnlockedVarJump; public bool playerUnlockedSideCast, playerUnlockedUpCast, playerUnlockedDownCast; //enemies stuff //shade public Vector2 shadePos; public string sceneWithShade; public Quaternion shadeRot; //The Bosses public bool THKDefeated; public bool SLMBDefeated; public bool GODDefeated; // Pickups and Chests data public HashSet<string> collectedPickups; // HashSet to store collected pickups 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 } } // Load existing data LoadSceneData(); if (!File.Exists(Application.persistentDataPath + "/save.bench.data")) { BinaryWriter writer = new BinaryWriter(File.Create(Application.persistentDataPath + "/save.bench.data")); } if (!File.Exists(Application.persistentDataPath + "/save.player.data")) { BinaryWriter writer = new BinaryWriter(File.Create(Application.persistentDataPath + "/save.player.data")); } if (!File.Exists(Application.persistentDataPath + "/save.shade.data")) { BinaryWriter writer = new BinaryWriter(File.Create(Application.persistentDataPath + "/save.shade.data")); } if (!File.Exists(Application.persistentDataPath + "/save.boss.data")) { BinaryWriter writer = new BinaryWriter(File.Create(Application.persistentDataPath + "/save.boss.data")); } if (!File.Exists(Application.persistentDataPath + "/save.pickups.data")) { BinaryWriter writer = new BinaryWriter(File.Create(Application.persistentDataPath + "/save.pickups.data")); } if (sceneNames == null) { sceneNames = new HashSet<string>(); } if (collectedPickups == null) { collectedPickups = new HashSet<string>(); } } #region Scenes Stuff 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); } } } 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(); sceneNames = new HashSet<string>(); for (int i = 0; i < sceneCount; i++) { string sceneName = reader.ReadString(); sceneNames.Add(sceneName); } } } else { sceneNames = new HashSet<string>(); } } #endregion #region Delete save data public void DeleteScenesData() { string path = Application.persistentDataPath + "/save.scenes.data"; if (File.Exists(path)) { File.Delete(path); Debug.Log("Scenes data deleted."); } } public void DeleteBenchData() { string path = Application.persistentDataPath + "/save.bench.data"; if (File.Exists(path)) { File.Delete(path); Debug.Log("Bench data deleted."); } } public void DeletePlayerData() { string path = Application.persistentDataPath + "/save.player.data"; if (File.Exists(path)) { File.Delete(path); Debug.Log("Player save data deleted."); } } public void DeleteShadeData() { string path = Application.persistentDataPath + "/save.shade.data"; if (File.Exists(path)) { File.Delete(path); Debug.Log("Shade save data deleted."); } } public void DeleteBossData() { string path = Application.persistentDataPath + "/save.boss.data"; if (File.Exists(path)) { File.Delete(path); Debug.Log("Boss save data deleted."); } } public void DeletePickupData() { string path = Application.persistentDataPath + "/save.pickups.data"; if (File.Exists(path)) { File.Delete(path); Debug.Log("Pickups save data deleted."); } } public void DeleteAllSaveData() { DeleteScenesData(); DeleteBenchData(); DeletePlayerData(); DeleteShadeData(); DeleteBossData(); DeletePickupData(); } #endregion #region Bench Stuff public void SaveBench() { using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(Application.persistentDataPath + "/save.bench.data"))) { writer.Write(benchSceneName); writer.Write(benchPos.x); writer.Write(benchPos.y); } } public void LoadBench() { string savePath = Application.persistentDataPath + "/save.bench.data"; if (File.Exists(savePath) && new FileInfo(savePath).Length > 0) { using(BinaryReader reader = new BinaryReader(File.OpenRead(Application.persistentDataPath + "/save.bench.data"))) { benchSceneName = reader.ReadString(); benchPos.x = reader.ReadSingle(); benchPos.y = reader.ReadSingle(); } } else { Debug.Log("Bench doesn't exist"); } } #endregion #region Player Stuff public void SavePlayerData() { using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(Application.persistentDataPath + "/save.player.data"))) { playerHealth = PlayerController.Instance.Health; writer.Write(playerHealth); playerMaxHealth = PlayerController.Instance.maxHealth; writer.Write(playerMaxHealth); playerHeartShards = PlayerController.Instance.heartShards; writer.Write(playerHeartShards); playerMana = PlayerController.Instance.Mana; writer.Write(playerMana); playerHalfMana = PlayerController.Instance.halfMana; writer.Write(playerHalfMana); playerManaOrbs = PlayerController.Instance.manaOrbs; writer.Write(playerManaOrbs); playerOrbShard = PlayerController.Instance.orbShard; writer.Write(playerOrbShard); playerOrb0fill = PlayerController.Instance.manaOrbsHandler.orbFills[0].fillAmount; writer.Write(playerOrb0fill); playerOrb1fill = PlayerController.Instance.manaOrbsHandler.orbFills[1].fillAmount; writer.Write(playerOrb1fill); playerOrb2fill = PlayerController.Instance.manaOrbsHandler.orbFills[2].fillAmount; writer.Write(playerOrb2fill); playerUnlockedWallJump = PlayerController.Instance.unlockedWallJump; writer.Write(playerUnlockedWallJump); playerUnlockedDash = PlayerController.Instance.unlockedDash; writer.Write(playerUnlockedDash); playerUnlockedVarJump = PlayerController.Instance.unlockedVarJump; writer.Write(playerUnlockedVarJump); playerUnlockedSideCast = PlayerController.Instance.unlockedSideCast; writer.Write(playerUnlockedSideCast); playerUnlockedUpCast = PlayerController.Instance.unlockedUpCast; writer.Write(playerUnlockedUpCast); playerUnlockedDownCast = PlayerController.Instance.unlockedDownCast; writer.Write(playerUnlockedDownCast); playerPosition = PlayerController.Instance.transform.position; writer.Write(playerPosition.x); writer.Write(playerPosition.y); lastScene = SceneManager.GetActiveScene().name; writer.Write(lastScene); } Debug.Log("saved player data"); } public void LoadPlayerData() { string savePath = Application.persistentDataPath + "/save.player.data"; if (File.Exists(savePath) && new FileInfo(savePath).Length > 0) { using(BinaryReader reader = new BinaryReader(File.OpenRead(Application.persistentDataPath + "/save.player.data"))) { playerHealth = reader.ReadInt32(); playerMaxHealth = reader.ReadInt32(); playerHeartShards = reader.ReadInt32(); playerMana = reader.ReadSingle(); playerHalfMana = reader.ReadBoolean(); playerManaOrbs = reader.ReadInt32(); playerOrbShard = reader.ReadInt32(); playerOrb0fill = reader.ReadSingle(); playerOrb1fill = reader.ReadSingle(); playerOrb2fill = reader.ReadSingle(); playerUnlockedWallJump = reader.ReadBoolean(); playerUnlockedDash= reader.ReadBoolean(); playerUnlockedVarJump= reader.ReadBoolean(); playerUnlockedSideCast= reader.ReadBoolean(); playerUnlockedUpCast = reader.ReadBoolean(); playerUnlockedDownCast = reader.ReadBoolean(); playerPosition.x = reader.ReadSingle(); playerPosition.y = reader.ReadSingle(); lastScene = reader.ReadString(); SceneManager.LoadScene(lastScene); PlayerController.Instance.transform.position = playerPosition; PlayerController.Instance.halfMana = playerHalfMana; PlayerController.Instance.Health = playerHealth; PlayerController.Instance.maxHealth = playerMaxHealth; PlayerController.Instance.heartShards = playerHeartShards; PlayerController.Instance.Mana = playerMana; PlayerController.Instance.manaOrbs = playerManaOrbs; PlayerController.Instance.orbShard = playerOrbShard; PlayerController.Instance.manaOrbsHandler.orbFills[0].fillAmount = playerOrb0fill; PlayerController.Instance.manaOrbsHandler.orbFills[1].fillAmount = playerOrb1fill; PlayerController.Instance.manaOrbsHandler.orbFills[2].fillAmount = playerOrb2fill; PlayerController.Instance.unlockedWallJump = playerUnlockedWallJump; PlayerController.Instance.unlockedDash = playerUnlockedDash; PlayerController.Instance.unlockedVarJump = playerUnlockedVarJump; PlayerController.Instance.unlockedSideCast = playerUnlockedSideCast; PlayerController.Instance.unlockedUpCast = playerUnlockedUpCast; PlayerController.Instance.unlockedDownCast = playerUnlockedDownCast; } Debug.Log("load player data"); Debug.Log(playerHalfMana); } else { Debug.Log("File doesn't exist"); PlayerController.Instance.halfMana = false; PlayerController.Instance.Health = PlayerController.Instance.maxHealth; PlayerController.Instance.Mana = 0.5f; PlayerController.Instance.heartShards = 0; PlayerController.Instance.unlockedWallJump = false; PlayerController.Instance.unlockedDash = false; PlayerController.Instance.unlockedVarJump = false; PlayerController.Instance.unlockedSideCast = false; PlayerController.Instance.unlockedUpCast = false; PlayerController.Instance.unlockedDownCast = false; } } #endregion #region Shade Stuff public void SaveShadeData() { using(BinaryWriter writer = new BinaryWriter(File.OpenWrite(Application.persistentDataPath + "/save.shade.data"))) { sceneWithShade = SceneManager.GetActiveScene().name; shadePos = Shade.Instance.transform.position; shadeRot = Shade.Instance.transform.rotation; writer.Write(sceneWithShade); writer.Write(shadePos.x); writer.Write(shadePos.y); writer.Write(shadeRot.x); writer.Write(shadeRot.y); writer.Write(shadeRot.z); writer.Write(shadeRot.w); } } public void LoadShadeData() { string savePath = Application.persistentDataPath + "/save.shade.data"; if (File.Exists(savePath) && new FileInfo(savePath).Length > 0) { using(BinaryReader reader = new BinaryReader(File.OpenRead(Application.persistentDataPath + "/save.shade.data"))) { sceneWithShade = reader.ReadString(); shadePos.x = reader.ReadSingle(); shadePos.y = reader.ReadSingle(); float rotationX = reader.ReadSingle(); float rotationY = reader.ReadSingle(); float rotationZ = reader.ReadSingle(); float rotationW = reader.ReadSingle(); shadeRot = new Quaternion(rotationX, rotationY, rotationZ, rotationW); } Debug.Log("Load shade data"); } else { Debug.Log("Shade doesn't exist"); } } #endregion #region The Bosses public void SaveBossData() { using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(Application.persistentDataPath + "/save.boss.data"))) { THKDefeated = GameManager.Instance.THKDefeated; SLMBDefeated = GameManager.Instance.SLMBDefeated; GODDefeated = GameManager.Instance.GODDefeated; writer.Write(THKDefeated); writer.Write(SLMBDefeated); writer.Write(GODDefeated); } } public void LoadBossData() { string savePath = Application.persistentDataPath + "/save.boss.data"; if (File.Exists(savePath) && new FileInfo(savePath).Length > 0) { using (BinaryReader reader = new BinaryReader(File.OpenRead(Application.persistentDataPath + "/save.boss.data"))) { THKDefeated = reader.ReadBoolean(); SLMBDefeated = reader.ReadBoolean(); GODDefeated = reader.ReadBoolean(); GameManager.Instance.THKDefeated = THKDefeated; GameManager.Instance.SLMBDefeated = SLMBDefeated; GameManager.Instance.GODDefeated = GODDefeated; } } else { Debug.Log("Boss doesnt exist"); } } #endregion #region Orbs Save Data public void AddCollectedPickup(string pickupID) { // Add pickup ID to collected pickups collectedPickups.Add(pickupID); SavePickups(); } public void SavePickups() { using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(Application.persistentDataPath + "/save.pickups.data"))) { // Save collected pickups writer.Write(collectedPickups.Count); foreach (string pickupID in collectedPickups) { writer.Write(pickupID); } } } public void LoadPickups() { string savePath = Application.persistentDataPath + "/save.pickups.data"; if (File.Exists(savePath) && new FileInfo(savePath).Length > 0) { using (BinaryReader reader = new BinaryReader(File.OpenRead(Application.persistentDataPath + "/save.pickups.data"))) { // Load collected pickups int numCollectedPickups = reader.ReadInt32(); for (int i = 0; i < numCollectedPickups; i++) { collectedPickups.Add(reader.ReadString()); } } } } #endregion }</code>
June 7, 2024 at 3:21 am #15028::<code>public class GameManager : MonoBehaviour { public string transitionedFromScene; public Vector2 platformingRespawnPoint; public Vector2 respawnPoint; [SerializeField] Bench bench; public GameObject shade; public bool THKDefeated = false; public bool SLMBDefeated = false; public bool GODDefeated = false; [SerializeField] private FadeUI pauseMenu; [SerializeField] private float fadeTime; public bool gameIsPaused; public static GameManager Instance { get; private set; } private void Awake() { SaveData.Instance.Initialize(); if(Instance != null && Instance != this) { Destroy(gameObject); } else { Instance = this; } if(PlayerController.Instance != null) { if (PlayerController.Instance.halfMana) { SaveData.Instance.LoadShadeData(); if(SaveData.Instance.sceneWithShade == SceneManager.GetActiveScene().name || SaveData.Instance.sceneWithShade == "") { Instantiate(shade, SaveData.Instance.shadePos, SaveData.Instance.shadeRot); } } } SaveScene(); DontDestroyOnLoad(gameObject); bench = FindObjectOfType<Bench>(); SaveData.Instance.LoadBossData(); SaveData.Instance.LoadPickups(); } public void ResetData() { SaveData.Instance.DeleteAllSaveData(); } private void Update() { if(Input.GetKeyDown(KeyCode.Escape) && !gameIsPaused) { pauseMenu.FadeUIIn(fadeTime); Time.timeScale = 0; gameIsPaused = true; } } public void UnpauseGame() { Time.timeScale = 1; gameIsPaused = false; } public void SaveScene() { string currentSceneName = SceneManager.GetActiveScene().name; SaveData.Instance.sceneNames.Add(currentSceneName); SaveData.Instance.SaveSceneData(); // Save scene names whenever a new scene is added } public void RespawnPlayer() { SaveData.Instance.LoadBench(); if (SaveData.Instance.benchSceneName != null) //load the bench's scene if it exists. { SceneManager.LoadScene(SaveData.Instance.benchSceneName); } if(SaveData.Instance.benchPos != null) //set the respawn point to the bench's position. { respawnPoint = SaveData.Instance.benchPos; } else { respawnPoint = platformingRespawnPoint; } PlayerController.Instance.transform.position = respawnPoint; StartCoroutine(UIManager.Instance.DeactivateDeathScreen()); PlayerController.Instance.Respawned(); } // Method to trigger pickup interaction event public void TriggerPickupInteract(string pickupID) { SaveData.Instance.AddCollectedPickup(pickupID); // Add pickup to SaveData } }</code>
June 7, 2024 at 3:22 am #15029::<code>public class SaveDataManager : MonoBehaviour { public void ResetSaveData() { string path = Application.persistentDataPath; // Delete all save files if they exist string[] saveFiles = { path + "/save.scenes.data", path + "/save.bench.data", path + "/save.player.data", path + "/save.shade.data", path + "/save.boss.data", path + "/save.pickups.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); } } Debug.Log("All save data has been reset."); } }</code>
June 7, 2024 at 3:22 am #15030::<code>public class PickupManager : MonoBehaviour { public static PickupManager Instance; private void Awake() { if(Instance != null && Instance != this) { Destroy(gameObject); } else { Instance = this; } DontDestroyOnLoad(gameObject); LoadAndDeactivateInteractedObjects(); // Load saved data and deactivate pickups } public void LoadAndDeactivateInteractedObjects() { HashSet<string> collectedPickups = SaveData.Instance.collectedPickups; print("Called"); // Deactivate pickups that have been collected foreach (GameObject pickup in GameObject.FindGameObjectsWithTag("Pickup")) { string pickupID = pickup.name; // Assuming the name of the object is its ID print(pickupID); if (collectedPickups.Contains(pickupID)) { print("found"); pickup.SetActive(false); // Deactivate the pickup print("deactivated"); } } } }</code>
June 7, 2024 at 3:22 am #15031::<code>public class IncreaseMaxHealth : MonoBehaviour { [SerializeField] GameObject particles; [SerializeField] GameObject canvasUI; [SerializeField] HeartShards heartShards; bool used; // Start is called before the first frame update void Start() { if (PlayerController.Instance.maxHealth >= PlayerController.Instance.maxTotalHealth) { Destroy(gameObject); } } private void OnTriggerEnter2D(Collider2D _collision) { if (_collision.CompareTag("Player") && !used) { GameManager.Instance.TriggerPickupInteract(gameObject.name); used = true; StartCoroutine(ShowUI()); } } IEnumerator ShowUI() { GameObject _particles = Instantiate(particles, transform.position, Quaternion.identity); Destroy(_particles, 0.5f); yield return new WaitForSeconds(0.5f); canvasUI.SetActive(true); heartShards.initialFillAmount = PlayerController.Instance.heartShards * 0.25f; PlayerController.Instance.heartShards++; heartShards.targetFillAmount = PlayerController.Instance.heartShards * 0.25f; StartCoroutine(heartShards.LerpFill()); yield return new WaitForSeconds(2.5f); SaveData.Instance.SavePlayerData(); canvasUI.SetActive(false); Destroy(gameObject); } }</code>
June 7, 2024 at 3:25 am #15032::And for playercontroller, I remove the LoadAndDeactivateInteractedObjects() method because I think it is unnecessary in this situation:
<code>public IEnumerator WalkIntoNewScene(Vector2 _exitDir, float _delay) { pState.invincible = true; //If exit direction is upwards if (_exitDir.y != 0) { rb.velocity = jumpForce * _exitDir; } //If exit direction requires horizontal movement if(_exitDir.x != 0) { xAxis = _exitDir.x > 0 ? 1 : -1; Move(); } Flip(); yield return new WaitForSeconds(_delay); pState.invincible = false; pState.cutscene = false; }</code>
June 7, 2024 at 11:11 am #15033::Your collectibles not reappearing after setting to new game means that the data for pickups is not being reset correctly.
Check point [2] of my latest comment here.
[Part 7] How can I let the game have “new game”
It seems like someone else had an issue where they’re data was not being deleted appropriately. This code seeks to not only delete the file paths, but also reset all the variables in the SaveData.cs that is being loaded.
If the code in [2], with some modifications to include your pickup variables, helped fix the issue, this would confirm that althought the save file is being deleted, the cached data for the variables are not. And they are only reset when you reopen your Unity Editor.
June 7, 2024 at 12:58 pm #15034::Still cannot, I try to use used = true or canvasUI.SetActive(true) to the ResetPickupData(), and it come out this error, by the way I use SaveDataManager to delete data not DeleteAllSaveData()
View post on imgur.com
June 7, 2024 at 12:59 pm #15035June 7, 2024 at 1:40 pm #15036::Please follow what is being done in the above post instead.
You cannot change the the Instance of your pickups when they have not been instantiated. Furthermore, setting the pickup’s bool
used
to true only makes them unable to be picked up.This also does not solve the issue since the problem may possibly only lie in the SaveData.cs retaining the information of
collectedPickups
until the Unity Editor is closed.
Instead of trying to reset the pickup scripts through your SaveDataManager.cs just instantiate the
SaveData.Instance
from the method instead, then try deleting the relevant information from there.SaveDataManager.cs
public void ResetPickupData() { SaveData.Instance.Initialize(); SaveData.Instance.collectedPickups.Clear(); }
June 7, 2024 at 1:53 pm #15037 -
AuthorPosts
- You must be logged in to reply to this topic.
Advertisement below: