I’m working on a project in Godot 4.3 and facing an issue with differentiating between clicks on GUI elements (like HUD buttons) and clicks intended for world interaction (e.g., moving a player character). Here’s the scenario:
Setup:
I have a CanvasLayer for HUD, which contains UI elements like buttons, health bars, and skill slots.
I also have a game world where clicks should trigger movement or actions, but only when they’re not on GUI elements.
Problem:
I’m using _unhandled_input in my world interaction scripts to handle clicks, but this also triggers when clicking on GUI elements.
I’ve tried using gui_pick() to detect clicks on GUI elements, but it seems to interfere with other events like button pressed signals. When a GUI element is clicked, I need the click to trigger the appropriate UI behavior and not propagate to _unhandled_input.
Current Approach:
I’m consuming the input in _gui_input for GUI elements and using event.accept() for clicks on the HUD.
However, this makes buttons in the HUD unresponsive because the event never reaches their pressed signal.
Desired Behavior:
Clicks on HUD elements should trigger their specific behavior (e.g., button pressed events).
Clicks outside the HUD should trigger world interaction like movement or targeting.
Questions:
Is there a recommended way to differentiate between GUI clicks and world interaction clicks in Godot 4?
How can I ensure that events for GUI elements like buttons still function correctly while preventing them from propagating to _unhandled_input?
Any guidance or examples would be greatly appreciated! Thank you in advance for your help.
Relevant Code
Here’s how I’m currently handling inputs:
# Player.gd
func _input(event: InputEvent) -> void:
if (event is InputEventMouseButton and event.pressed) or (event is InputEventScreenTouch and event.is_pressed()):
var position = get_global_mouse_position()
# Logic to move the player or interact with the game
# UILayer.gd
func _input(event: InputEvent) -> void:
if event is InputEventMouseButton and event.pressed:
var clicked_node = get_viewport().gui_pick(event.position)
if clicked_node and is_instance_valid(clicked_node):
print("Clicked on UI element:", clicked_node.name)
get_viewport().set_input_as_handled()
Desired Behavior
Clicking on UI elements like Button should stop the input from propagating to the player (or other gameplay elements).
Clicking outside of UI elements should allow for gameplay interaction, such as moving the player character.