Forum begins after the advertisement:
[part 10] Boss do not dead
Home › Forums › Video Game Tutorial Series › Creating a Metroidvania in Unity › [part 10] Boss do not dead
- This topic has 13 replies, 3 voices, and was last updated 1 week, 3 days ago by Terence.
-
AuthorPosts
-
December 8, 2024 at 1:02 am #16688::
Hello guys After checking and testing, the boss was could dead before, but then when i decide to make the boss door in the part 10, I checked again and now the boss doesn’t dead anymore as you can see as the image below, i already hit the boss to -4 hp but the boss still walking and hitting me
The boss still can hit me and i can hit the boss as well I had already tried that remove the spawn script and put the boss to the room from the start but the boss still doesn’t dead after the health reduce to 0 here the boss codeusing System.Collections; using System.Collections.Generic; using UnityEngine; public class CorruptedMonk : Enemy { public static CorruptedMonk Instance; [SerializeField] private AudioClip changestateSound; [Header("Attacking setting")] [SerializeField] public Transform sideAttackTransform, upAttackTransform, downAttackTransform; [SerializeField] public Vector2 sideAttackArea, upAttackArea, downAttackArea; [Space(5)] public float attackRange; public float attackTimer; [Header("Groundcheck setting")] [SerializeField] private Transform groundcheck; [SerializeField] private Transform wallCheck; [SerializeField] private float groundchecky = 0.2f; [SerializeField] private float groundcheckx = 0.5f; [SerializeField] private LayerMask isground; int hitCounter; bool stunned, canStunned; bool alive; public bool damagedPlayer = false; [HideInInspector] public float runSpeed; [HideInInspector] public bool facingRight; [HideInInspector] public bool parrying; private void Awake() { if(Instance != null && Instance != this) { Destroy(gameObject); } else { Instance = this; } } // Start is called before the first frame update protected override void Start() { base.Start(); Sr = GetComponentInChildren<SpriteRenderer>(); anim = GetComponentInChildren<Animator>(); ChangeState(EnemyStates.Monk_State1); alive = true; } public bool grounded; public bool isonGround() { if (Physics2D.Raycast(groundcheck.position, Vector2.down, groundchecky, isground) || Physics2D.Raycast(groundcheck.position + new Vector3(groundcheckx, 0, 0), Vector2.down, groundchecky, isground) || Physics2D.Raycast(groundcheck.position + new Vector3(-groundcheckx, 0, 0), Vector2.down, groundchecky, isground) ) { grounded = true; return true; } else { grounded = false; return false; } } public bool touchWall() { if (Physics2D.Raycast(wallCheck.position, Vector2.down, groundchecky, isground) || Physics2D.Raycast(wallCheck.position + new Vector3(groundcheckx, 0, 0), Vector2.down, groundchecky, isground) || Physics2D.Raycast(wallCheck.position + new Vector3(-groundcheckx, 0, 0), Vector2.down, groundchecky, isground) ) { return true; } else { return false; } } private void OnDrawGizmos() { Gizmos.color = Color.yellow; Gizmos.DrawWireCube(sideAttackTransform.position, sideAttackArea); Gizmos.DrawWireCube(upAttackTransform.position, upAttackArea); Gizmos.DrawWireCube(downAttackTransform.position, downAttackArea); } // Update is called once per frame protected override void Update() { base.Update(); if(health <= 0 && alive) { Death(0); } if (!attacking) { attackCountdown -= Time.deltaTime; } if (stunned) { rb.velocity = Vector2.zero; } } public void Flip() { if (Move.Instance.transform.position.x < transform.position.x && transform.localScale.x > 0) { transform.eulerAngles = new Vector2(transform.eulerAngles.x, 180); facingRight = false; } else { transform.eulerAngles = new Vector2(transform.eulerAngles.x, 0); facingRight = true; } } protected override void UpdateEnemyStates() { if(Move.Instance != null) { switch (GetCurrentEnemyStates) { case EnemyStates.Monk_State1: canStunned = true; attackTimer = 4; runSpeed = speed; dmgMake = 2; break; case EnemyStates.Monk_State2: new WaitForSeconds(1f); anim.SetBool("Changestate", false); audioSource.PlayOneShot(changestateSound); new WaitForSeconds(1f); canStunned = true; attackTimer = 2; runSpeed = speed * 1.1f; dmgMake = 3; break; } } } protected override void OnCollisionStay2D(Collision2D _other) { } public void ResetAllAttack() { attacking = false; StopCoroutine(TriplePunch()); StopCoroutine(SweepKick()); StopCoroutine(Parry()); StopCoroutine(payback()); flyingKichAttack = false; } #region attacking #region variables [HideInInspector] public bool attacking; [HideInInspector] public float attackCountdown; [HideInInspector] public Vector2 moveToPosition; [HideInInspector] public bool flyingKichAttack; public GameObject divingCollider; public GameObject pillar; #endregion #region Control public void AttackHandler() { if(currentState == EnemyStates.Monk_State1) { if(Vector2.Distance(Move.Instance.transform.position,rb.position) <= attackRange) { StartCoroutine(TriplePunch()); } else { StartCoroutine(SweepKick()); } } if (currentState == EnemyStates.Monk_State2) { if (Vector2.Distance(Move.Instance.transform.position, rb.position) <= attackRange) { StartCoroutine(TriplePunch()); } else { int attackChoose = Random.Range(1,2); if(attackChoose == 1){ StartCoroutine(SweepKick()); } if (attackChoose == 2) { FlyingKickAttackJump(); } } } } #endregion #region Stage1 IEnumerator TriplePunch() { attacking = true; rb.velocity = Vector2.zero; anim.SetTrigger("Punch"); Debug.Log("First punch"); yield return new WaitForSeconds(1f); anim.ResetTrigger("Punch"); anim.SetTrigger("Punch"); Debug.Log("Second punch"); yield return new WaitForSeconds(0.7f); anim.ResetTrigger("Punch"); anim.SetTrigger("Punch"); Debug.Log("Third punch"); yield return new WaitForSeconds(0.3f); anim.ResetTrigger("Punch"); ResetAllAttack(); } IEnumerator SweepKick() { Flip(); attacking = true ; Debug.Log("Kich start"); anim.SetBool("Kick",true); yield return new WaitForSeconds(1f); Debug.Log("Kich hit"); anim.SetBool("Kick", false); damagedPlayer = false; ResetAllAttack() ; } IEnumerator Parry() { attacking=true ; rb.velocity = Vector2.zero; Debug.Log("start Parry"); anim.SetBool("Parry", true); yield return new WaitForSeconds(0.8f); anim.SetBool("Parry", false); parrying = false ; ResetAllAttack(); } #endregion #endregion public override void EnemyHit(float _DmgDone, Vector2 _hitDirection, float _hitForce) { if (!stunned) { if (!parrying) { if (canStunned) { hitCounter++; if(hitCounter >= 6) { ResetAllAttack(); StartCoroutine(Stunned()); } } base.EnemyHit(_DmgDone, _hitDirection, _hitForce); StartCoroutine(Parry()); } else { StopCoroutine(Parry()); parrying=false; ResetAllAttack(); StartCoroutine(payback()); } } else { StopCoroutine(Stunned()); anim.SetBool("Stun", false ); stunned = false; } if(health > 30) { ChangeState(EnemyStates.Monk_State1); } if(health <= 15) { anim.SetBool("Changestate", true); ChangeState(EnemyStates.Monk_State2); } if(health <= 0 && alive) { Death(0); } } IEnumerator payback() { attacking = true; rb.velocity = Vector2.zero; anim.SetTrigger("Punch"); yield return new WaitForSeconds(0.5f); anim.ResetTrigger("Punch"); ResetAllAttack(); } #region Stage2 void FlyingKickAttackJump() { attacking = true ; moveToPosition = new Vector2(Move.Instance.transform.position.x, rb.velocity.y +2); flyingKichAttack = true ; anim.SetBool("Jump", true); } public void Dive() { anim.SetBool("FlyingKick",true); anim.SetBool("Jump", false); } private void OnTriggerEnter2D(Collider2D collision) { if (collision.GetComponent<Move>() != null && flyingKichAttack) { collision.GetComponent<Move>().takeDmg(dmgMake * 2); Move.Instance.playerStateList.recoilingX = true; // Disable the attack to prevent further damage flyingKichAttack = false; } } public void DivingPillar() { Vector2 _impactPoint = groundcheck.position; float _spawnDistance = 5f; for (int i = 0; i < 5; i++) { Vector2 _pillarSpawnPointRight = _impactPoint + new Vector2(_spawnDistance, 0); Vector2 _pillarSpawnPointLeft = _impactPoint - new Vector2(_spawnDistance, 0); Debug.Log($"Diving Pillar {i} has a spawn distance of {_spawnDistance}"); Debug.Log($"Spawning right pillar at: {_pillarSpawnPointRight}"); Instantiate(pillar, _pillarSpawnPointRight, Quaternion.Euler(0, 0, 0)); Debug.Log($"Spawning left pillar at: {_pillarSpawnPointLeft}"); Instantiate(pillar, _pillarSpawnPointLeft, Quaternion.Euler(0, 0, 0)); Debug.DrawLine(_impactPoint, _pillarSpawnPointRight, Color.red, 5f); Debug.DrawLine(_impactPoint, _pillarSpawnPointLeft, Color.blue, 5f); _spawnDistance += 2; } ResetAllAttack(); } #endregion public IEnumerator Stunned() { stunned = true; hitCounter = 0; anim.SetBool("Stun", true); yield return new WaitForSeconds(4f); anim.SetBool("Stun", false); stunned = false; } protected override void Death(float _destroyTime) { ResetAllAttack(); alive = false; rb.velocity = new Vector2(rb.velocity.x, -25); anim.SetTrigger("Die"); } public void DestroyAfterDeath() { Destroy(gameObject); } }
I’m sure that i do not touching anything to this code when i made the boss door. I will give the boss door script too
using System.Collections; using System.Collections.Generic; using UnityEngine; public class SpawnBoss : MonoBehaviour { // Start is called before the first frame update public static SpawnBoss Instance; [SerializeField] Transform spawnPoint; [SerializeField] GameObject boss; [SerializeField] Vector2 exitDir; bool callOnce; BoxCollider2D col; private void Awake() { if(Instance != null && Instance != this) { Destroy(gameObject); } else { Instance = this; } } void Start() { col = GetComponent<BoxCollider2D>(); } // Update is called once per frame void Update() { } private void OnTriggerEnter2D(Collider2D collision) { if (collision.CompareTag("Player")) { if (!callOnce) { StartCoroutine(WalktoRoom()); callOnce = true; } } } IEnumerator WalktoRoom() { StartCoroutine(Move.Instance.WalktonewScene(exitDir, 1)); Move.Instance.playerStateList.incutscene = true; yield return new WaitForSeconds(1f); col.isTrigger = false; Instantiate(boss, spawnPoint.position, Quaternion.identity); } public void isnotTrigger() { col.isTrigger = true; } }
And as the video of part 10 i add the boss spawn into the monk event script
void DestroyAfterDeath() { SpawnBoss.Instance.isnotTrigger(); CorruptedMonk.Instance.DestroyAfterDeath(); }
Please help me to fix this. Tks you guys
December 8, 2024 at 1:44 am #16691::Ok so for some reason, I manage to fix the boss death with the help of GPT, but the boss door doesn’t change it state into trigger again and my character got stuck in the boss room and cannot get out AS you can see firstly in the console, the boss is dead
but here the boss door still off the trigger
and for some reason, after defeated the boss, the game didn’t save the boss status eitheri already have the debug in the monk event script but as you can see at the console picture, the boss doesn’t got save
void DestroyAfterDeath() { SpawnBoss.Instance.isnotTrigger(); CorruptedMonk.Instance.DestroyAfterDeath(); GameManager.Instance.bossDeafeated = true; SaveData.Instance.saveBoss(); Debug.Log("Save boss data"); SaveData.Instance.savePlayerData(); }
using System.Collections; using System.Collections.Generic; using UnityEngine; using System.IO; using UnityEngine.SceneManagement; [System.Serializable] public struct SaveData { //player public static SaveData Instance; public HashSet<string> sceneNames; public string altersceneName; public Vector2 alterPos; public int playerHealth; public int playerHeartShards; public float playerMana; public Vector2 playerPosition; public string lastScene; public int playerMaxHealth; public bool playerUnlockWallJump; public bool playerUnlockDash; public bool playerUnlockDbJump; //boss public bool BossDeafeated; public void Initialize() { if (!File.Exists(Application.persistentDataPath + "/save.alter.data")) { BinaryWriter writer = new BinaryWriter(File.Create(Application.persistentDataPath + "/save.alter.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.boss.data")) { BinaryWriter writer = new BinaryWriter(File.Create(Application.persistentDataPath + "/save.boss.data")); } if (sceneNames == null) { sceneNames = new HashSet<string>(); } } public void saveAlter() { using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(Application.persistentDataPath + "/save.alter.data"))) { writer.Write(altersceneName); writer.Write(alterPos.x); writer.Write(alterPos.y); Debug.Log("saved Max Health: " + playerMaxHealth); Debug.Log("saved heart shards: " + playerHeartShards); } } public void loadAlter() { string savePath = Application.persistentDataPath + "/save.alter.data"; if (File.Exists(savePath) && new FileInfo(savePath).Length > 0) { using(BinaryReader reader = new BinaryReader(File.OpenRead(Application.persistentDataPath + "/save.alter.data"))) { altersceneName = reader.ReadString(); alterPos.x = reader.ReadSingle(); alterPos.y = reader.ReadSingle(); Debug.Log("saved Max Health: " + playerMaxHealth); Debug.Log("saved heart shards: " + playerHeartShards); } } } public void savePlayerData() { string filePath = Application.persistentDataPath + "/save.player.data"; using (BinaryWriter writer = new BinaryWriter(File.Create(filePath))) { // Save player health and max health playerHealth = Move.Instance.Health; writer.Write(playerHealth); playerMaxHealth = Move.Instance.MaxHealth; writer.Write(playerMaxHealth); // Save player mana playerMana = Move.Instance.Mana; writer.Write(playerMana); // Save player unlock abilities playerUnlockWallJump = Move.Instance.unlockWalljump; writer.Write(playerUnlockWallJump); playerUnlockDash = Move.Instance.unlockDash; writer.Write(playerUnlockDash); playerUnlockDbJump = Move.Instance.unlockDbJump; writer.Write(playerUnlockDbJump); // Save player position playerPosition = Move.Instance.transform.position; writer.Write(playerPosition.x); writer.Write(playerPosition.y); // Save player heart shards playerHeartShards = Move.Instance.heartShards; writer.Write(playerHeartShards); // Save the last scene name lastScene = SceneManager.GetActiveScene().name; writer.Write(lastScene); Debug.Log("Player data saved successfully."); Debug.Log("Before saving - Health: " + playerHealth + ", Max Health: " + playerMaxHealth + ", Heart Shards: " + playerHeartShards); } } public void loadPlayerData() { string filePath = Application.persistentDataPath + "/save.player.data"; if (File.Exists(filePath)) { using (BinaryReader reader = new BinaryReader(File.OpenRead(filePath))) { // Load all necessary data playerHealth = reader.ReadInt32(); playerMaxHealth = reader.ReadInt32(); playerMana = reader.ReadSingle(); playerUnlockWallJump = reader.ReadBoolean(); playerUnlockDash = reader.ReadBoolean(); playerUnlockDbJump = reader.ReadBoolean(); playerPosition.x = reader.ReadSingle(); playerPosition.y = reader.ReadSingle(); playerHeartShards = reader.ReadInt32(); lastScene = reader.ReadString(); Debug.Log($"Loaded Health: {playerHealth}, Max Health: {playerMaxHealth}"); // Load the scene and register a callback to set player data after the scene loads SceneManager.sceneLoaded += OnSceneLoaded; SceneManager.LoadScene(lastScene); } } else { Debug.Log("Save file not found. Initializing default values."); Move.Instance.Health = Move.Instance.MaxHealth; Move.Instance.heartShards = 0; Move.Instance.Mana = 0.5f; Move.Instance.unlockWalljump = false; Move.Instance.unlockDash = false; Move.Instance.unlockDbJump = false; } } // Callback function to set player data after the scene has loaded private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { // Unregister the event to avoid it being called multiple times SceneManager.sceneLoaded -= OnSceneLoaded; // Set the player's data once the scene has fully loaded Move.Instance.transform.position = playerPosition; Move.Instance.MaxHealth = playerMaxHealth; Move.Instance.Health = playerHealth; Move.Instance.Mana = playerMana; Move.Instance.unlockWalljump = playerUnlockWallJump; Move.Instance.unlockDash = playerUnlockDash; Move.Instance.unlockDbJump = playerUnlockDbJump; Move.Instance.heartShards = playerHeartShards; Debug.Log($"After loading - Health: {Move.Instance.Health}, Max Health: {Move.Instance.MaxHealth}, Position: {playerPosition}"); } public void saveBoss() { if (!File.Exists(Application.persistentDataPath + "/save.boss.data")) //if file doesnt exist, well create the file { BinaryWriter writer = new BinaryWriter(File.Create(Application.persistentDataPath + "/save.boss.data")); } using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(Application.persistentDataPath + "/save.boss.data"))) { BossDeafeated = GameManager.Instance.bossDeafeated; writer.Write(BossDeafeated); } } public void loadBoss() { 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"))) { BossDeafeated = reader.ReadBoolean(); GameManager.Instance.bossDeafeated = BossDeafeated; } } } }
December 8, 2024 at 4:25 pm #16697::Are there any errors in your Console when the boss dies?
Add this to the
Awake()
function of yourSpawnBoss
script and show me your console when the boss dies:private void Awake() { if(Instance != null && Instance != this) { Debug.LogWarning("Multiple SpawnBoss scripts found!"); Destroy(gameObject); } else { Instance = this; } }
December 8, 2024 at 8:03 pm #16699::So there is no errors messages appear in the console when the boss die, only some warning about the sound clip is null
i had already change the spawn boss code as you saidprivate void Awake() { if(CorruptedMonk.Instance != null) { Destroy(CorruptedMonk.Instance); callOnce = false; col.isTrigger = true; } if(GameManager.Instance.bossDeafeated) { callOnce = true; } if(Instance != null && Instance != this) { Debug.LogWarning("Multiple SpawnBoss scripts found!"); Destroy(gameObject); } else { Instance = this; } }
and the moment the boss is spawn, nothing happend either
December 8, 2024 at 11:36 pm #16700December 9, 2024 at 6:55 am #16701::It kinda hard to said that it was done. I solved it but it just a temporary method. By adding some code into the save boss and boss death like this
public void saveBoss() { string savePath = Application.persistentDataPath + "/save.boss.data"; // Ensure the save file is created and written properly using (BinaryWriter writer = new BinaryWriter(File.Create(savePath))) { BossDeafeated = GameManager.Instance.bossDeafeated; // Get the defeat state writer.Write(BossDeafeated); // Write the state to the file } Debug.Log("Boss save file created and state saved: " + BossDeafeated); }
protected override void Death(float _destroyTime) { if (!alive) return; // Prevent multiple death calls Debug.Log("Boss is dead!"); alive = false; ResetAllAttack(); // Ensure attacks are stopped rb.velocity = Vector2.zero; // Stop movement anim.SetTrigger("Die"); // Play death animation // Optionally disable collider or make the boss "inactive" GetComponent<Collider2D>().enabled = false; GameManager.Instance.bossDeafeated = true; SaveData.Instance.saveBoss(); // Destroy object after delay Destroy(gameObject, _destroyTime); }
the game could said it work by the boss save file in the save game folder. But the game didn’t save it automatically. I need to press p to save it by this code in game manager
private void Update() { if(Input.GetKeyDown(KeyCode.P)) { SaveData.Instance.savePlayerData(); } if (Input.GetKeyDown(KeyCode.Escape) && !gameIsPause) { pauseMenu.fadeUIIn(fadeTime); Debug.Log("Pausing game. GameManager active: " + this.gameObject.activeSelf); Time.timeScale = 0; gameIsPause = true; } }
I would tried to deploy the old code to see is it made any difference. Update: the old way still work but for some reason, the door still stuck and do not set trigger again after i come and defeated the boss Another update: Old way alway make an error is Out of Stream. When i change back to the new way, the error is disapear and i see that if i turn of the game and turn on again, the door of the boss room is set to trigger again and player could go through it normally with out making it spawn the boss again.
December 9, 2024 at 1:11 pm #16704::Your new approach appears to handle saving the boss’s defeated state more effectively, and it also avoids the “Out of Stream” error seen with the old method. It seems like your solution resolves the immediate issue with the boss’s door being triggered properly after a game restart. Here’s a breakdown of what you’ve done well and areas that could use improvement:
Key Observations:
-
Persistent Data Path:
- You’re saving the boss state in the
Application.persistentDataPath
. This is the correct approach for ensuring the save data persists across sessions.
- You’re saving the boss state in the
-
Improved Save Logic:
- Writing to a file using a
BinaryWriter
ensures the save process is robust. - The inclusion of
GameManager.Instance.bossDeafeated
ensures the state is centralized and correctly tracked.
- Writing to a file using a
-
Boss Death and Save Call:
- Automatically saving the boss state upon its death (
SaveData.Instance.saveBoss()
) ensures the state is updated immediately. - Stopping the boss’s movement, resetting attacks, and playing a death animation are all logical steps in the
Death
method.
- Automatically saving the boss state upon its death (
-
Manual Save via Key Press:
- Using
Input.GetKeyDown(KeyCode.P)
to save is a good temporary solution, but not ideal for long-term usability.
- Using
Suggestions for Improvement:
-
Automate Saving:
- Instead of relying on pressing
P
to save manually, you can integrate an autosave system triggered by significant game events, such as defeating a boss or passing a checkpoint. For example:
public void TriggerAutoSave() { SaveData.Instance.savePlayerData(); Debug.Log("Game autosaved."); }
- Instead of relying on pressing
-
Separate Save Logic:
- Consider separating the save logic for the boss and the door. If the door’s state is dependent on the boss’s state, ensure this is handled during game load:
public void LoadGameState() { string savePath = Application.persistentDataPath + "/save.boss.data"; if (File.Exists(savePath)) { using (BinaryReader reader = new BinaryReader(File.OpenRead(savePath))) { GameManager.Instance.bossDeafeated = reader.ReadBoolean(); Debug.Log("Loaded boss state: " + GameManager.Instance.bossDeafeated); } } }
-
Debugging the Door Issue:
- Ensure the door checks the boss’s state during game initialization. For example:
void UpdateDoorState() { if (GameManager.Instance.bossDeafeated) { door.SetTrigger("Open"); Debug.Log("Door is set to open."); } else { Debug.Log("Door remains locked."); } }
Call this method during the level’s start or after loading the game state.
-
Optimize the
Update
Method:- Your
Update
method could become bloated if many conditions are checked every frame. Consider event-driven triggers instead, e.g., using Unity Events or custom events to manage pauses and saves.
- Your
-
File I/O Error Handling:
- Add error handling to your save and load logic to prevent crashes or data corruption in edge cases:
try { using (BinaryWriter writer = new BinaryWriter(File.Create(savePath))) { writer.Write(BossDeafeated); } } catch (Exception ex) { Debug.LogError("Failed to save boss data: " + ex.Message); }
- Add error handling to your save and load logic to prevent crashes or data corruption in edge cases:
Conclusion:
Your current implementation resolves several issues effectively, but automating saves and debugging the door logic would further improve the user experience. With these refinements, your game will have a more robust save system and seamless state management.
December 9, 2024 at 1:35 pm #16705December 9, 2024 at 3:57 pm #16706::Your current setup saves the boss’s defeat properly and fixes the “Out of Stream” error. The save triggers automatically when the boss dies, and the door works fine after restarting the game. However, needing to press
P
for manual saves isn’t ideal.To improve, add an autosave feature for key events like defeating a boss. Also, ensure the door checks the boss’s state during game load to update correctly. For smoother performance, replace constant checks in
Update
with event-based triggers. Adding error handling will make the save/load system more reliable and user-friendly.And as sir said above can you please provide the console error for the old way?
December 9, 2024 at 10:20 pm #16709::I got some mistake here, the error is not Out of Stream error. So if i tried this code in the save boss function which is the old way to reproduce the error.
public void saveBoss() { if (!File.Exists(Application.persistentDataPath + "/save.boss.data")) //if file doesnt exist, well create the file { BinaryWriter writer = new BinaryWriter(File.Create(Application.persistentDataPath + "/save.boss.data")); } // Ensure the save file is created and written properly using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(Application.persistentDataPath + "/save.boss.data"))) { BossDeafeated = GameManager.Instance.bossDeafeated; // Get the defeat state writer.Write(BossDeafeated); // Write the state to the file } Debug.Log("Boss save file created and state saved: " + BossDeafeated); }
The error appear like this
As you could see, the boss must be death, the death function has been called in the console but the boss didn’t destroy. He can still hit me, using hit skill and i can hit him either.December 9, 2024 at 10:26 pm #16710::But if i using this way
public void saveBoss() { string savePath = Application.persistentDataPath + "/save.boss.data"; // Ensure the save file is created and written properly using (BinaryWriter writer = new BinaryWriter(File.Create(savePath))) { BossDeafeated = GameManager.Instance.bossDeafeated; // Get the defeat state writer.Write(BossDeafeated); // Write the state to the file } Debug.Log("Boss save file created and state saved: " + BossDeafeated); }
The game could work normally but the door didn’t trigger. I must stop the game and re opened to make the door is trigger. as you could see in the recording below Door stuck record
December 10, 2024 at 12:57 am #16712::The 2nd way of saving is the correct one. The reason your door is not firing has nothing to do with the saving, I suspect.
It is because this line is not firing after your boss dies.
void DestroyAfterDeath() { SpawnBoss.Instance.isnotTrigger(); CorruptedMonk.Instance.DestroyAfterDeath(); GameManager.Instance.bossDeafeated = true; SaveData.Instance.saveBoss(); Debug.Log("Save boss data"); SaveData.Instance.savePlayerData(); }
You need to figure out why. Perhaps the SpawnBoss object is disabled when the boss dies?
December 11, 2024 at 2:40 am #16728::Sorry for replying late, I got a long day. So about this, I think the problem is just like as you said but doesn’t know why it happend. The code still works after defeating the boss and turn off and turn on the game again. So it mean it work but not at the time at the boss was be beaten. And I really have no idea what cause of this trouble
December 11, 2024 at 11:10 pm #16739::A simple way to check for this is add the following lines to both your functions:
void DestroyAfterDeath() { print("DestroyAfterDeath() running"); SpawnBoss.Instance.isnotTrigger(); CorruptedMonk.Instance.DestroyAfterDeath(); GameManager.Instance.bossDeafeated = true; SaveData.Instance.saveBoss(); Debug.Log("Save boss data"); SaveData.Instance.savePlayerData(); }
public void isnotTrigger() { print("isnotTrigger() running"); col.isTrigger = true; }
After that, kill the boss and see whether both the messages we coded to print is firing. The reason your trigger is not starting is because
isnotTrigger()
isn’t working, but we need to find out where is your code failing.If both messages don’t appear, then this means that
DestroyAfterDeath()
isn’t firing — in that case, we will have to figure out which function(s) are supposed to callDestroyAfterDeath()
, and why it isn’t firing.Does that make sense?
-
-
AuthorPosts
- You must be logged in to reply to this topic.
Advertisement below: