Quick answer: Parent Control’s mouse_filter = MOUSE_FILTER_STOP. World listens via _unhandled_input — if UI consumed, it never fires.
Pause menu. Click Resume. Player also fires gun in the world. Click was processed twice because the parent Control passed the event through.
The Symptom
Button works and world action triggers from the same click. Reverse case: UI behind game prevents world input.
The Fix
# PauseMenu (Control root)
mouse_filter = Control.MOUSE_FILTER_STOP # consume events
# Game world input listener
extends Node2D
func _unhandled_input(event):
# only fires if UI didn't consume
if event is InputEventMouseButton and event.pressed:
fire()
Use _unhandled_input for world — not _input — so consumed events don’t reach it. UI gets first dibs via the GUI pipeline.
Custom Controls
func _gui_input(event):
if event is InputEventMouseButton and event.pressed:
do_action()
accept_event() # important
Verifying
Click button: action fires once, world doesn’t react. Click outside the panel: world reacts normally.
“mouse_filter Stop. accept_event. World on _unhandled_input.”
Related Issues
For RPC silent, see RPC silent. For just_pressed, see just_pressed.
Stop the event. World stays calm.