I actually have an answer for this!
But first, the obvious answer: if you can reuse the PlayerInput
object in your main scene (that is, don’t disable it, and don’t create a new one in the additive scene), that will be the most efficient way to solve this problem.
But sometimes you really want a new PlayerInput
, perhaps because the new scene really is a new scene and the old scene is not being displayed or used at all. That’s what I’m doing for the “map view” in my game – add a new scene additively, then disable everything in the old scene.
The Answer
Surprisingly easy: disable the old PlayerInput object before the new scene loads.
FindObjectOfType<PlayerInput>().gameObject.SetActive(false);
// load scene or whatever
var loader = SceneManager.LoadSceneAsync("MapScene", LoadSceneMode.Additive);
while (!loader.isDone)
{
yield return null;
}
or something like that will do it. Obviously it disables input when the scene starts to load and doesn’t restore it until the scene has finished loading, which might not be acceptable for long load times, but it’s good enough for simple cases.
Explanation
When you create (or specifically, enable) a PlayerInput
object, here’s part of the code that runs:
AssignPlayerIndex();
InitializeActions();
AssignUserAndDevices();
ActivateInput();
which causes the devices (e.g. your mouse and keyboard) to be assigned to that user. If you create another PlayerInput
, there are no devices left to bind to that user! At least, not the same devices.
If you disable the PlayerInput
, this is some of the code that runs:
DeactivateInput();
UnassignUserAndDevices();
UninitializeActions();
and as you can see, the devices are unbound.
Binding and unbinding devices is probably expensive, which is why it’d be nice to avoid if you can.