Forum begins after the advertisement:


[Part 7] Player does not respawn at the correct respawn point

Home Forums Video Game Tutorial Series Creating a Metroidvania in Unity [Part 7] Player does not respawn at the correct respawn point

Viewing 6 posts - 1 through 6 (of 6 total)
  • Author
    Posts
  • #13917
    Alberto Fogli
    Participant

    Hi everyone,

    When i try to save the “bench” coordinates and die to see if i respawn back at the correct point, it load for a second at the correct position, but then i get teleported back at starting point and an error appears

    NullReferenceException: Object reference not set to an instance of an object
    UIManager+<DeactivateDeathScreen>d__8.MoveNext () (at Assets/Scripts/UIManager.cs:45)
    UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress)

    Here is the code:

    Bench code:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.SceneManagement;
    
    public class SavePoint : MonoBehaviour
    {
        [SerializeField]public bool interacted;
    
        private void OnTriggerStay2D(Collider2D collision)
        {
            if(collision.CompareTag("Player") && Input.GetButtonDown("Interact"))
            {
                interacted = true;
    
                SaveData.Instance.stoneSceneName = SceneManager.GetActiveScene().name;
                SaveData.Instance.stonePos = new Vector2(gameObject.transform.position.x, gameObject.transform.position.y);
                SaveData.Instance.SaveStone();
            }
        }
    }
    

    Save 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;
    
        //stone data
        public string stoneSceneName;
        public Vector2 stonePos;
    
        //player data
        public int playerHealth;
        public Vector2 playerPos;
        public string lastScene;
    
        public void Initialize()
        {
            if(!File.Exists(Application.persistentDataPath + "/save.stone.data"))
            {
                BinaryWriter writer = new BinaryWriter(File.Create(Application.persistentDataPath + "/save.stone.data"));
            }
        }
    
        public void SaveStone()
        {
            using(BinaryWriter writer = new BinaryWriter(File.OpenWrite(Application.persistentDataPath + "/save.stone.data")))
            {
                writer.Write(stoneSceneName);
                writer.Write(stonePos.x);
                writer.Write(stonePos.y);
            }
        }
    
        public void LoadStone()
        {
            string savePath = Application.persistentDataPath + "/save.stone.data";
            if (File.Exists(savePath) && new FileInfo(savePath).Length > 0)
            {
                using(BinaryReader reader = new BinaryReader(File.OpenRead(Application.persistentDataPath + "/save.stone.data")))
                {
                    stoneSceneName = reader.ReadString();
                    stonePos.x = reader.ReadSingle();
                    stonePos.y = reader.ReadSingle();
                }
            }
        }
    }

    Game manager code:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.SceneManagement;
    
    public class GameManager : MonoBehaviour
    {
        public string transitionedFromScene;   
        public static GameManager Instance { get; private set; }
    
        public Vector2 respawnPoint;
        [SerializeField] SavePoint stone;
        private void Awake()
        {
            SaveData.Instance.Initialize();
            if(Instance != null && Instance != this)
            {
                Destroy(gameObject);
            }
            else
            {
                Instance = this;
            }
    
            DontDestroyOnLoad(gameObject);
    
            stone = FindObjectOfType<SavePoint>();
        }
    
        public void RespawnPlayer()
        {
            SaveData.Instance.LoadStone();
    
            if(SaveData.Instance.stoneSceneName != null)
            {
                SceneManager.LoadScene(SaveData.Instance.stoneSceneName);
            }
    
            Debug.Log(SaveData.Instance.stonePos);
    
            if(SaveData.Instance.stonePos.x != 0 && SaveData.Instance.stonePos.y != 0)
            {
                respawnPoint.y = SaveData.Instance.stonePos.y + 1.358f;
                respawnPoint.x = SaveData.Instance.stonePos.x;
            }
            else
            {
                respawnPoint = new Vector2(-3f, -2.58f);
            }
    
            PlayerMovement.Instance.transform.position = respawnPoint;
            StartCoroutine(UIManager.Instance.DeactivateDeathScreen());
            PlayerLife.pl.Respawn();
    
        }
    }
    

    UIManager code:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    
    public class UIManager : MonoBehaviour
    {
        [SerializeField]Slider slider;
        [SerializeField]PlayerLife player;
        public static UIManager Instance;
        [SerializeField] GameObject deathScreen;
        public GameObject inventory;
        public SceneFader sceneFader;
    
        private void Awake()
        {
            if(Instance != null && Instance != this)
            {
                Destroy(gameObject);
            }
            else
            {
                Instance = this;
            }
            DontDestroyOnLoad(gameObject);
            
            sceneFader = GetComponentInChildren<SceneFader>();
        }
    
        public IEnumerator ActivateDeathScreen()
        {
            yield return new WaitForSeconds(0.8f);
            StartCoroutine(sceneFader.Fade(SceneFader.FadeDirection.In));
    
            yield return new WaitForSeconds(0.8f);
            deathScreen.SetActive(true);
        }
    
        public IEnumerator DeactivateDeathScreen()
        {
            yield return new WaitForSeconds(0.2f);
            deathScreen.SetActive(false);
    
            StartCoroutine(sceneFader.Fade(SceneFader.FadeDirection.Out));
            slider.value = player.maxHealth;
        }
    
        // Start is called before the first frame update
        void Start()
        {
            
            slider.maxValue = player.maxHealth;
            slider.value = player.maxHealth;
        }
    
        public void UpdateUIHealtbar(int currentHealth)
        {
            slider.value = currentHealth;
        }
    }
    

    Thanks in advance to everyone

    #13921
    Joseph Tang
    Moderator

    If you are able to, could you record a video/screenshot of:
    1) Your player dying and respawning
    2) Dying and respawning all in one scene without prior save files.
    3) The inspector of both UIManager & Player scripts while dying.

    My theory is that from your error, NullReferenceException, something is not assigned/found correctly. That something is then directed in the following line “UIManager+d__8.MoveNext () (at Assets/Scripts/UIManager.cs:45)” meaning the error involves your UIManager.cs, DeactivateDeathScreen() method in line 45. which would be this:
    slider.value = player.maxHealth;

    Check for 2 things here:
    1) Check if the slider & player is set in the inspector of the UIManager.
    2) Check that the slider/Player is set active while deactivate deathscreen is functioning. [Likely the script is trying to set the slider but the slider/player is not currently active while trying to set it.

    As for the Save point situation,
    I have found issues with dying outside of the scene that the savepoint is set. If you die while outside of the scene you seem to respawn at the transition point in between scenes instead of the bench. I will have to test this out for a fix but otherwise, check if you respawn correctlly if you die in the same scene as the bench.

    #13924
    Alberto Fogli
    Participant

    Ok, here are the video:
    1) https://imgur.com/a/BYON0dv
    2) https://imgur.com/a/1tCnO5c
    3) https://imgur.com/a/MkCBwpT (in the player inspector it doesn’t change anything)

    Yeah, in the UIManager the player script became missing for some reasons.

    When i tried without doing the saving part (so just with the interaction with the bench) it worked fine

    if(stone != null)
            {
                if (stone.interacted)
                {
                    respawnPoint.y = stone.transform.position.y + 1.358f; 
                    respawnPoint.x = stone.transform.position.x;   
                }
                else
                {
                    respawnPoint = new Vector2(-3f, -2.58f);
                }
                
            }
            else
            {
                respawnPoint = new Vector2(-3f, -2.58f);
            }
    #13925
    Joseph Tang
    Moderator

    I don’t know which part of the code you changed, however the issue should be that your Player does not include DontDestroyOnLoad(gameObject); in Awake() or Start() [We put it in Awake() for this series].

    The point of DontDestroyOnLoad(gameObject); is to allow you to change scenes/reload scenes with the same gameobjects [Player + Menu + Other essential Managers].
    Thus, when the scene is reloaded, the Player is destroyed and the Player instance called by your UIManager and other scripts lose the Player and cannot call or set anything with the Player as they are not set again after reloading the scene.
    Similarly, since your Player isn’t following the scene change, when you reloaded the current scene, they “spawn” at their start point because that’s their scene start position with the reload scene.

    Thus, simply put the code in and it should work. If it doesn’t I’ll need a bit of time to test to see what other issue it could be.

    #13927
    Alberto Fogli
    Participant

    Now it works perfectly! Thanks a lot, i wasted 2 days trying to figure it out why it didn’t work.

    #13929
    Joseph Tang
    Moderator

    Great to hear! If you have any other issues always watch out for the scene Console and it’s error messages.

    We have a post for NullReferenceException if you want to take a look at it:

    What NullReferenceException errors are (and how to fix them) in Unity

    Otherwise, if you can’t figure it out for this series, you can make another question post on the forum.

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

Go to Login Page →


Advertisement below: