I will be the first to admit I am fairly new to Godot, so I am still learning the ropes on debugging. An unfortunate issue I ran into was the culmination of some architectural mistakes, incorrect assumptions, and lack of knowledge how to properly debug Godot.
The Issue
I had made some small test projects, with buttons that seemed to work fine. As I worked on a more substantial project, it came time to create a menu for the user, and suddenly, things went off the rails. The issue? No UI component would accept mouse clicks.
The Bad Assumptions
Now, I made lots of incorrect assumptions. This happened because of:
Leaning on previous experience thinking I knew what was up.
Read the docs. Unless I misunderstood, the code seemed to check out per examples there.
History. I remember smaller projects, where a button click would do something.
Deep diving on the Internet. Lots of similar issues or even the same issue and not fully understanding the root causes.
Thought the click coordinates were not in the right spot (since the elements did not react, like hovering over a button didn’t change it, even though it was correct in the scene in terms of setup).
The Bad Code
Now, the code itself was correct per se. I lost a lot of time trying to debug, including adding code simply to confirm via _input()
where I was clicking. Essentially all combinations of debugging attempts confirmed activity was happening but no events were being processed by the UI components, regardless of component.
Fail Attempt One
All UI elements are based on the Control Node type. It contains a property in the config called mouse_filter, found in the Mouse→Filter
section of the Inspector
. (More information on GUI controls can be found here.). This mouse_filter setting, which is stop, pass, and ignore, dictates what the node should do. In Godot, for a button to handle a press event from the mouse, it should set this value to stop. However, all nodes above it in the tree in your scene, should have their mouse_filter
set to ignore.
To quickly summarize the mouse_filter
options:
Stop: The node will consume the event.
Pass: The node will consume the event and pass it to the parent node to consume.
Ignore: The node discards the event.
Even knowing this, and confirming many times the settings were correct, it did not work.
Fail Attempt Two
After reaching deeper into Godot history, I was thinking maybe changes related to how signal processing was handled is causing me an issue. Maybe I forgot a step in terms of config, as in Project→Project Settings, Input Map
. I actually had keyboard events working, and they never failed to work for me. As I was using the function _input()
, I thought maybe mouse clicks were supposed to be done in a similar way. I never fully went down this path, but it did lead to more searching.
I even found references to events failing or being inconsistent, including sometimes on Mac silicon based Macs. However, that seemed extreme (and often from older posts, before Godot 4.0 was even out).
However, after much resetting signals, changing event code, testing input maps, still no progress.
Break Time
Not totally. I decided to go back to new projects and try again, and as expected, it worked. So it brought my thinking right back to something that must be wrong in this specific project.
Third Attempt is the Charm
Finally, hope! This project I have worked on requires transitioning between scenes. A TransitionManager
was created earlier in the project to fade between scenes. This will matter in a moment.
While randomly searching I found a post about one small feature of the Godot debugger. There is a panel named Misc, which happens to show the node that processed the most recent event. I was not aware of this. Immediately I checked it out. Sure enough, while running just a single scene, not the entire project, it referenced a component in a different scene. You guessed it, the TransitionManager
.
The TransitionManager
has a ColorRect
, which is a Control
node type. I blindly assumed a random color rectangle would never block events. In fact, I never thought about another scene being the issue at all. What was learned here is, when you autoload a scene (which is in Project→Project Settings, Globals, Autoload
), these scenes last for the duration of the project runtime. By design, visual components generally have mouse_filter set to stop, to avoid causing downstream issues in your scene. I, like many, presumed most would be set to pass or ignore. I was wrong.
The Debugger Misc tab clearly showed the ColorRect was stopping the pressed()
event. I jumped over to the TransitionManager scene, went to the ColorRect
Mouse→Filter
properties and set it to ignore. Restarted the scene, everything works just as expected.
Summary
While it took more time then I would have liked, I did learn quite a few things along the way, as well as got much better understanding and moving around the Godot editor. To summarize the issue, if click events are not working as you expect:
Confirm the immediate scene tree Control-based nodes have the correct mouse_filter settings.
Double check your signal is configured to the correct script location and function.
Running the problematic scene, check inside the Misc debugger panel to see which node consumed the click event.
Additional Debugging
One area that didn’t really help fix the issue did give me insight into event processing was logging. For example, in your scenes script:
func _input(event) -> void:
if (event.as_text() == "Left Mouse Button"):
print(event.as_text())
print(event.get_property_list())
Events sent by the OS, such as a mouse click, can be captured in the _input(event)
function. You would use this function only to capture the event at the time it happened. I used this for example to get coordinates, etc to see what might be wrong. Meaning more directly, this function gave me output!
While informative, it sent me down a very incorrect path in terms of the issue. There is a lot to processing input, whether a one event item like clicking a menu button, to holding down multiple keys at the same time. You can find more information on which functions to use and when in the official docs here.