Forum begins after the advertisement:
[Part 7 Bug Fixes] New Game Error, Respawn Issues, Optimized Bench Interaction
Home › Forums › Video Game Tutorial Series › Creating a Metroidvania in Unity › [Part 7 Bug Fixes] New Game Error, Respawn Issues, Optimized Bench Interaction
- This topic has 1 reply, 2 voices, and was last updated 2 months ago by Chloe Lim.
-
AuthorPosts
-
May 10, 2024 at 6:57 pm #14619::
This is a supplementary post written for Part 7 of our Metroidvania series, and it aims to address 2 things:
- Missing information in the video, and;
- Address common issues / questions that readers run into, and possible solutions for these questions.
For this part, there are less bugs to be addressed, However, check this post to see if your issue is addressed there:
[Part 7] SceneFader NullReferenceException and SaveData EndOfStreamException
For convenience, below are the links to the article and the video:
- Article Link: https://blog.terresquall.com/2023/07/creating-a-metroidvania-like-hollow-knight-part-7/
- Video Link: https://youtu.be/hEEOefW3MHU
Table of Contents
Missing Information in the Video
- Starting fresh game causes player to not be able to land or load save data.
- Player respawns at 0 health after leaving game from death. + Moving Player corpse.
- Bench interaction is inconsistent.
- Capping Player falling speed.
Common Issues
Missing Information in the Video
1. Starting fresh game causes player to not be able to land or load save data.
[Caused by
LoadPlayerData()
trying to load a save file when the player has never calledSavePlayerData()
, and thus prevents the rest ofStart()
to not be called.]- Move the called
LoadPlayerData()
to the bottom ofStart()
. This will make sure the rest of theStart()
code is called and allows the player to play the game even ifLoadPlayerData()
fails. - Move the if statement which checks for half mana, to below the
LoadPlayerData()
.
// Start is called before the first frame update void Start() { pState = GetComponent<PlayerStateList>(); rb = GetComponent<Rigidbody2D>(); sr = GetComponent<SpriteRenderer>(); anim = GetComponent<Animator>();
SaveData.Instance.LoadPlayerData();gravity = rb.gravityScale;if (halfMana) { UIManager.Instance.SwitchMana(UIManager.ManaState.HalfMana); } else { UIManager.Instance.SwitchMana(UIManager.ManaState.FullMana); }Mana = mana; manaStorage.fillAmount = Mana; Health = maxHealth; SaveData.Instance.LoadPlayerData(); if (halfMana) { UIManager.Instance.SwitchMana(UIManager.ManaState.HalfMana); } else { UIManager.Instance.SwitchMana(UIManager.ManaState.FullMana); } }
2. Player respawns at 0 health after leaving game from death. + Moving Player corpse.
[Caused by
SavePlayerData()
taking place after the death of the player, and not respawning to reset this fact.]- Add a code to PlayerController.cs
Start()
to call theRespawnPlayer()
method in GameManager.cs, as well as set thepState.alive
to false if the Player’s health is at [0]. This will respawn the player if they are loaded in with 0 health. - In the
Death()
method, set the player’sRigidbody2D
to freeze position, andBoxCollider2D
to false. This prevents the dead player from acting as a collider or being influenced by gravity to fall or be pushed by other moving entities to a scene transition. - In the
Respawned()
method, reset theRigidbody2D
constraints and reenable the BoxCollider2D.
// Start is called before the first frame update void Start() { ... { UIManager.Instance.SwitchMana(UIManager.ManaState.FullMana); } if (Health == 0) { pState.alive = false; GameManager.Instance.RespawnPlayer(); } } IEnumerator Death() { ... anim.SetTrigger("Death"); rb.constraints = RigidbodyConstraints2D.FreezePosition; GetComponent[BoxCollider2D]().enabled = false; yield return new WaitForSeconds(0.9f); ... } public void Respawned() { if(!pState.alive) { rb.constraints = RigidbodyConstraints2D.None; rb.constraints = RigidbodyConstraints2D.FreezeRotation; GetComponent[BoxCollider2D]().enabled = true; pState.alive = true; ... } }
Note: The “[]” for BoxCollider2D are to be replaced by angle brackets, but I cannot use it on HTML.
3. Bench interaction is inconsistent.
[Caused by inefficient code, explanation in link below]
public class Bench : MonoBehaviour { bool inRange = false; public bool interacted; // Update is called once per frame 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(); Debug.Log("benched"); } }
private void OnTriggerStay2D(Collider2D _collision) { if(_collision.CompareTag("Player") && Input.GetButtonDown("Interact")) { 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(); Debug.Log("benched"); } }void OnTriggerEnter2D(Collider2D _collision) { if(_collision.CompareTag("Player")) inRange = true; } private void OnTriggerExit2D(Collider2D _collision) { if (_collision.CompareTag("Player")) { inRange = false; } } }
4. Capping Player falling speed.
- Set the player’s velocity in
Jump()
to it’s current velocity, but clamp the y value to a new variable,maxFallingSpeed
.
[SerializeField] private int maxFallingSpeed; //max fall speed void Jump() { ... if (Input.GetButtonUp("Jump") && rb.velocity.y > 3) { pState.jumping = false; rb.velocity = new Vector2(rb.velocity.x, 0); } rb.velocity = new Vector2(rb.velocity.x, Mathf.Clamp(rb.velocity.y, -maxFallingSpeed, rb.velocity.y)); anim.SetBool("Jumping", !Grounded()); }
Common Issues
5. Unable to click on Respawn Button.
[This solution is only if you are unable to interact with the button (It is not highlighted/changes colour when hovered by mouse and cannot be clicked):]
- 1. Ensure that your Button is at the bottom of the Canvas Hierarchy [Move the game object with the button to the last position]. This will place your button in front of all other game objects in the canvas, preventing Raycast blocking.
- 2. Turn off “RayCast Target” on your other game objects.
- 3. Ensure your scene has an “EventSystem” component.
How to fix an unclickable Button in Unity’s Canvas UI system
That will be all for Part 7. Hopefully this can help you on any issues you may have. However, if you find that your issues weren’t addressed or is a unique circumstance, you can submit a forum post to go into detail on your problem for further assistance.
has upvoted this post. October 28, 2024 at 8:41 am #16197 -
AuthorPosts
- You must be logged in to reply to this topic.