I have a custom options menu build. When user clicks outside it’s area, I want to close it (visible=false).
func _unhandled_input(event: InputEvent) → void:
if (Input.is_action_just_pressed(“leftClick”)):
battle_ui.options_menu.visible=false
It works nicely when player clicks on normal game screen, but of course it does not work when user clicks on any other control nodes, because those events are handled.
How can I add this “battle_ui.options_menu.visible=false” to all control nodes without writing code for each of those nodes separately ?
Or maybe there is some other smart method that will achieve similar result but will be done differently?
I guess you can go with different implementations, depending on what works best for your use-case.
You can have a main ui controller, that checks if there is a click, and then checks if the click happens in one of the ui elements, and closes the rest.
You can also add individual script on each ui element. They can each check a click, and if the click happens on them, you don’t close that ui element.
“You can have a main ui controller, that checks if there is a click, and then checks if the click happens in one of the ui elements, and closes the rest.”
You can connect mouse_entered() and mouse_exited() signals of each UI element to a function in your main ui controller. And keep a list of if mouse is on the ui element or not. You can keep that data in a Dictionary variable.
So something like this in your main ui controller
@export var ui_element_node_A : Control
@export var ui_element_node_B : Control
# etc.. for each ui element
var dict : Dictionary
#mouse_entered() signal of UI Element A is connected to this function
func mouse_entered_ui_element_A():
dict[ui_element_node_A]= true
#mouse_exited() signal of UI Element A is connected to this function
func mouse_exited_ui_element_A():
dict[ui_element_node_A]= false
# etc.. for each ui element
func _unhandled_input(event: InputEvent) → void:
if Input.is_action_just_pressed(“leftClick”):
for ui_node in dict:
ui_node.visible = dict[ui_node]
Use a Control node as the parent of your menu covering the outside area (set its anchors to Full Rect for example) with its Control.mouse_filter set to Stop. This Control node will stop input events going to other Controls and you will be able to react to the mouse events it detects.
This was the first idea that occurred to me too, checking for mouse exit/enter events.
It might make it simpler to add a back panel to your options menu, so that its not a popup box on top of many other content boxes on the screen (which force you to use detection on everything).
For example:
Create a full screen, transparent parent panel/control, with options panel on top of it.