Mouse in Area2D not detected and no, it's not a "control mouse filter" issue

Godot Version

4.4.1

Question

I have set up a scene to detect mouse hoowering on various type of objects. I use composition. So I put this scene under any node I want to be able to detect hoowering, set up the collision area size, and that’s it.

The scene is an Area2D with a CollisionShape2D. Code is as follows. “g.” refers to “global.gd”, a singleton. That singleton is responsible to get the signal and send it to whoever is interested

extends Area2D
class_name mouse_detector
@export var area_size: int = 16
signal mouse_in

func _ready() → void:
$CollisionShape2D.shape = RectangleShape2D.new()
$CollisionShape2D.shape.size = Vector2(area_size, area_size)
$CollisionShape2D.position = Vector2(area_size/2, -area_size/2)
mouse_in.connect(g._on_mouse_detector_mouse_entered)
mouse_entered.connect(_on_mouse_entered)
mouse_exited.connect(g._on_mouse_detector_mouse_exited)

func _on_mouse_entered():
mouse_in.emit(get_parent())

And here is what you find in global.gd:

signal mouse_in
signal mouse_out
func _on_mouse_detector_mouse_entered(o) → void:
mouse_in.emit(o)

func _on_mouse_detector_mouse_exited() → void:
mouse_out.emit()

Piece of cake, right?

Problem is, mouse is randomly not detected.
Sometime it is, in a position DIFFERENT from where it should.
Sometimes, triggers/detriggers if I zoom in or out the camera (which I can do using the mouse wheel btw).
Often, triggers in the right position if I click the mouse left button, but it should not. As you see above nothing is related to mouse click. Yes there is a control node somewhere on the tree that listens for clicks, its code is as follows:

extends Control
class_name in_game_control

@export var parent: Node

signal left_mouse_click

func _ready() → void:
pass # Replace with function body.

func _input(event):
# Mouse in viewport coordinates.
if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_LEFT and event.is_pressed():
accept_event()
left_mouse_click.emit()

I am enabling display of collision shapes in editor, they are where they should, b4 you ask.

OF COURSE all in any control node is fine for mouse input: everything is set to “pass”.

Odd?
I did not tell you the whole story tough.
I have two viewports. And I suspect that THERE is the problem, somehow.
In fact, on the right viewport everything is working fine as it should.
It’s only in the left one that things go crazy.
I suspect everything is related to that. Also the only viewport that has zooming is the left one, the right one has not, scale = 1 and no camera zoom ever.

But even if my suspect is correct… well now what?!

I’m depressed. There is ALWAYS an issue with signal for mouse position. I am really pissed off, Godot somehow always makes some specific thing more difficult than they should (control nodes, anyone?). I will end up putting a get_global_mouse_position in a process, then check for various rectangles if the mouse position is inside them, and that’s it. Maybe.

But maybe someone here understands my problem and has a solution? I would love so.

SubViewports won’t automatically propagate input events unless they are a child of a SubViewportContainer. If your SubViewport is not inside a SubViewportContainer then you’ll need to manually propagate the input events with Viewport.push_input() More info here Using InputEvent — Godot Engine (stable) documentation in English (read carefully the section How does it work?)

Your in_game_control Control is overriding the _input() function which will always process the input event independently of what Control.mouse_filter you selected. So, it won’t matter where you make a left click, it will always accept_event() it and stop propagating the input event to other nodes (in that specific viewport).

Did you enable Viewport.physics_object_picking in the viewport you are not getting the clicks/mouse events from physics bodies like areas?

Thanks for your reply.

Yes my subviewports are childrens of subviewport containers.
Yes they have physics object picking.

Maybe I was not clear enough: it’s not a problem of input being eaten by some events.
If so, two things would happen, different from what is actually happening:

  • no input would be detected, ever, on the left viewport. But actually this is not true: events are “randomly” detected
  • no input would be detected on the right viewport. But this is not true, the right viewport (which is too son of a subviewport container of course) actually works fine

To check it, I also removed my in_game_control node, nothing changes.
Therefore I think there is something else going on.

So.

I made a test.

There was another “input handling” function in my code and it’s in my custom_mouse script, which detects mouse wheel to zoom in and out.

I deleted it.

Now, on the left viewport, every time the mouse is over an item that should be detected, it IS detected provided I use the mouse wheel.

This is crazy.

There is nothing detecting the mouse wheel now. Nor there are other control events.

Also, I tried running the scene contained in the left_viewport alone (it is a Node2D with childs).
So no more “double viewport” issues, and not any problem with containers.
The left scene has no control nodes too, now (it had the input_handling but I removed it, as well as I removed the input handling in the custom_mouse scene).

There is absolutely no “active” control node, nothing detecting inputs now. The only thing is, the mouse_detector scenes on my objects. But now the signal is sent only if I use the mouse wheel, which is not referenced ANYWHERE ANYMORE in the code.

I’m going insane.

So I finally found it.
After many tests, with some things working and some others not
In the environment, the floor is a color rect, instantiated via code, and it was the problem.

So problem solved.

However, my 2 cents. I think that the Godot developers should REALLY consider to set the default of control nodes to mouse pass, not to mouse stop.
I find myself always changing manually this property. Almost never if not never at all I need mouste to stop. When you do your UI with nested controls just to have everything aligned up properly (containers of various kind etc), having to manyally set everything to pass is a chore, and you may end up forgetting something. I did forget this, because it was in the code not in the editor.

Thank you all

This topic is discussed here:

Feel free to give a thumbs-up to that proposal.

1 Like