This code presented in this lecture has a very nasty bug that becomes apparent if:
- The game object containing this script is not disabled in your scene hierarchy by default, AND
- you subscribe to events in your playercontroller in OnEnable and OnDisable
- you rely upon events as part of restore / scene loading
private void OnEnable()
{
playerController.enabled = false;
Time.timeScale = 0;
}
private void OnDisable()
{
playerController.enabled = true;
Time.timeScale = 1;
}
With the bug, what happens is your player controller will get disabled when the scene loads, which will make it unsubscribe from events. You will then miss events needed as part of scene loading / restore state. The window will eventually get disabled by the ShowHide script but in the meantime you will miss important events needed as part of scene restoration. It is very hard to track this bug down if you don’t know to look for it.
I implemented a simple (but not robust) fix - move ShowHide code from Awake to Start. One can also disable the Pause UI gameobject in the scene view.
My fix is not robust in my mind because we are using playerController.enabled
in many places.
Question: What’s a more robust way of preventing user input when you don’t want it?
I was thinking of modifying PlayerController with a boolean and methods to ascertain if we want to accept or not accept user input. But after getting burned by weird race conditions, I am seeking advice. I’d also like the solution to be compatible with this from Brian’s tips and tricks.
In the past, I might have reached for a GameManager singleton class to centralize coordination of game state and make sure pause, resume, suspend user input are all handled properly. I am increasingly leaning that way, especially seeing how often we call static methods like GameObject.Find* for the player and saving wrapper. Looking for suggestions.
Option 1: Updated PlayerController (no game manager)
private bool isInputSuspended;
//by default we want input not to be suspended I think
private void Update()
{
if (IsInputSuspended()) return;
// normal update code continues
}
public bool IsInputSuspended()
{
return isInputSuspended;
}
public void SuspendInput()
{
isInputSuspended = true;
}
public void AcceptInput()
{
isInputSuspended = false;
}