Reloading Scene Causes Reference Exception with Input Functions

Hi, I have a bunch of scripts for handling inputs using the new Unity Input system and it all works quite well. Everything works perfectly and as expected until I reload the scene. I’m not sure if I’m missing something obvious and I thought I was handling OnEnable and OnDisable correctly for these inputs. Say I’m playing the game (on the initial load) and then delete the Game Object in the inspector, these issues dont occur.

When I click ‘escape’ (pause button) after reloading the scene:
Error: MissingReferenceException while executing ‘performed’ callbacks of ‘Player/Pause/Keyboard/escape’
Error: Mssing ReferenceException: the object of type ‘Canvas Group’ has been destroyed but you are still trying to access it.

Ill use the most basic of my scripts since this issue happens on all of them (that have input references).

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
using Cinemachine;
using UnityEngine.UI;
using DG.Tweening;
using UnityEngine.SceneManagement;

public class PauseManager : MonoBehaviour
{
    [SerializeField]
    private InputActionReference _pauseActionControl;
    [SerializeField]
    private InputActionReference _mouseLook;
    private bool _isPaused;
    [SerializeField]
    private CanvasGroup _pauseUi;
    [SerializeField]
    private CanvasGroup _comboUi;
    [SerializeField]
    private CanvasGroup _playerUi;
    [SerializeField]
    private CinemachineInputProvider _inputProvider;
    [SerializeField]
    private PlayerController _player;
   
    private void OnEnable()
    {
        _pauseActionControl.action.Enable();
        _pauseActionControl.action.performed += ctx => OnPauseButton();
    }

    private void OnDisable()
    {
        _pauseActionControl.action.performed -= ctx => OnPauseButton();
        _pauseActionControl.action.Disable();       
    }

    private void Start()
    {
        _isPaused = false;
        Cursor.lockState = CursorLockMode.Locked;
        _inputProvider.XYAxis = _mouseLook;
        Cursor.visible = false;
        _pauseUi.alpha = 0;
        _playerUi.alpha = 1;
        _comboUi.alpha = 1;
        Time.timeScale = 1.0f;       
    }

    private void OnPauseButton()
    {
        if (_isPaused)
        {
            _isPaused = false;
            Cursor.lockState = CursorLockMode.Locked;
            Cursor.visible = false;
            _pauseUi.alpha = 0;
            _playerUi.alpha = 1;
            _comboUi.alpha = 1;
            _player.canMove = true;
            _inputProvider.XYAxis = _mouseLook;
            Time.timeScale = 1.0f;
           
        }
        else
        {
            _isPaused = true;
            Cursor.lockState = CursorLockMode.None;
            Cursor.visible = true;
            _pauseUi.alpha = 1;
            _playerUi.alpha = 0;
            _comboUi.alpha = 0;
            _player.canMove = false;
            _inputProvider.XYAxis = null;
            Time.timeScale = 0f;           
        }
    }   

    public void OnReloadButton()
    {
        SceneManager.LoadScene(SceneManager.GetActiveScene().name);
    }
}

I was having a similar issue when reloading a scene. I was subscribing to some input events in Start() for an action (started and cancelled.) The fix was to unsubscribe to them in OnDisable().

Hi @Pur333 . You need to convert your anonymous delegate to a named method like this: (there are other ways to do this but this is the most straightforward)

    private void OnEnable()
    {
        _pauseActionControl.action.Enable();
        _pauseActionControl.action.performed += OnPauseButton;
    }
    private void OnDisable()
    {
        _pauseActionControl.action.performed -= OnPauseButton;
        _pauseActionControl.action.Disable();    
    }

When you use an anonymous delegate like you are, you’re adding one instance to performed, and then later trying to remove a completely different instance.

3 Likes

Just bumped into this issue, that I fixed thanks to your commend @andrew_oc !

I think it would be useful to update the documentation to show that you should unsubscribe from the performed action in OnDisable, and potentially a warning about using anonymouse delegate too.

1 Like