When loading a scene as additive to another one how can we make the scene modal so that the user can’t interact with the previous scene ? (as in the case of a modal dialogue box) where the user can’t press or click on an object in the bottom scene.
I would do that as a prefab not a scene
There’s nothing about a scene that can control whether it’s objects are interacted with or not. You would have to write some sort of script that maybe somehow references all of the intractable objects that you want, and disables/enables whatever components make them intractable or not.
You could add a background panel to the scene you’re loading in that covers the whole screen. Then, when your modal loads, that panel will block the user from interacting with anything behind it. Just make sure that this panel is behind your modal, and that ‘raycast target’ is ticked.
This is what I do. Giant invisible colliders that catch all input and prevent it from going through to the rest of the game.
You can do a similar thing for keyboard input. Catch all of your Input.GetKey stuff in a single script. Then feed it out to the rest of your game from there. If for some reason you want to stop all input, simply put an appropriate bool in your input script.
Why not just a screen space canvas?
Screen space canvas won’t always intercept input, depends on how you process it.
I think I usually do loading screens as a prefab that gets loaded on demand (although an additive scene can be more or less the same).
Since I develop for VR i use world space canvases only with custom raycasting so granted I’m no expert on screen space stuff. But yeah, I use prefabs for these things too
In order to use scene space canvases or other such click blockers, you would first need to rely on one and only one input funnel, and Unity doesn’t force you to do that. You’d have to plan for it from the start.
A click blocker also goes out the window if you’re building for a controller input scheme.
This assumes that your game is controlled only via your UI. If that’s the case then this is a pretty decent solution.
If that’s not the case, then this is a higher level design question that you’ll want to address fairly early on in your project. How will you manage input and ensure that objects only receive/use input while the game is in appropriate states?
One approach I’ve used is to have InputConsumers and an InputManager. The manager enables/disables InputConsumers depending on what object the player is controlling, the game’s state, and so on.
It could be worth checking out Unity’s new input system. I haven’t checked it out myself, it might have something built in to handle some of this for you?
Yes. Which you should be doing. Unity’s multiple input funnels don’t play nicely with each other. So even if you don’t need this kind of blocking, you should be sticking to one kind of input funnel.
Which reminds me. I did a video a while back on blocking clicks in general, which might be relevant to the OP.
https://www.youtube.com/watch?v=EVZiv7DLU6E
It basically says funnel all your clicks through the event system, and let the event system take care of it. But there are a couple of other suggestions there if you need to do it in code.
Every day I see code like Input.GetKey(“Space”) this is the reason why you should abstract things like that
in our game we are very specific which canvas can receive input plus all menus are world space so we shouldnt disable input from player
public ConfirmYieldInstruction Init(Transform parent, string text, string title, ConfirmResult confirmFlags)
{
this.parent = parent;
Text.text = text;
Title.text = title;
transform.SetParent(parent);
var confirm = confirmFlags != ConfirmResult.None;
ConfirmYieldInstruction result = null;
foreach (var button in Buttons)
button.Button.gameObject.SetActive(false);
if (confirm)
{
result = new ConfirmYieldInstruction();
var canvas = GetComponent<Canvas>();
InputModule.Instance.AddCanvas(canvas);
foreach (var button in Buttons)
{
if ((button.Flag & confirmFlags) == button.Flag)
{
button.Button.gameObject.SetActive(true);
button.Button.onClick.AddListener(() =>
{
InputModule.Instance.RemoveCanvas(canvas);
result.Result = button.Flag;
});
}
}
}
return result
}
When mouse input is locked to camera (like fps or third person camera), you have a modal toggle for menus where you enable mouse pointer and you deactivate the component that maps mouse input to camera rotation.
When mouse input isn’t locked to camera (or similar) you generally want the topmost collision from pointer raycast.
yepp, but if you look at how people code, they dont abstract from Unity raw input. Then that get harder.