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

Viewing 2 posts - 1 through 2 (of 2 total)
  • Author
    Posts
  • #14619
    Joseph Tang
    Level 13
    Moderator
    Helpful?
    Up
    1
    ::

    This is a supplementary post written for Part 7 of our Metroidvania series, and it aims to address 2 things:

    1. Missing information in the video, and;
    2. 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:


    Table of Contents

    Missing Information in the Video

    1. Starting fresh game causes player to not be able to land or load save data.
    2. Player respawns at 0 health after leaving game from death. + Moving Player corpse.
    3. Bench interaction is inconsistent.
    4. Capping Player falling speed.

    Common Issues

    1. Unable to click on Respawn Button.

    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 called SavePlayerData(), and thus prevents the rest of Start() to not be called.]

    • Move the called LoadPlayerData() to the bottom of Start(). This will make sure the rest of the Start() code is called and allows the player to play the game even if LoadPlayerData() 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 the RespawnPlayer() method in GameManager.cs, as well as set the pState.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’s Rigidbody2D to freeze position, and BoxCollider2D 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 the Rigidbody2D 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.
    #16197
    Chloe Lim
    Level 10
    Moderator
    Helpful?
    Up
    1
    ::

    In the conclusion script for part 7’s article, the player controller scripts, some pState variables were uppercase pState or lower case pstate, do maintain the lower casing of the variable to avoid errors

    has upvoted this post.
Viewing 2 posts - 1 through 2 (of 2 total)
  • You must be logged in to reply to this topic.

Go to Login Page →


Advertisement below: