godot: Area2D mouse_entered and mouse_exited signals not called in Viewport

Godot version:

Tested with 4f697f73a5ac567c1dc22ce44a7fab98f619dfe3

OS/device including version:

Linux Mint 19.1 tessa 64 Bit

Issue description:

When using Area2D in a Viewport the mouse_entered and mouse_exited signals are never called.

Steps to reproduce: Use the test project. When you run the project you see two godot-icons. Both icons are unmodified instances of Area2D.tscn. The one on the left is contained in a Viewport and does not print any messages when it should receive mouse enter and exit signals. The one on the right will print messages when the mouse enters/exits the icon.

Additional info: The UI node’s mouse filter is set to pass. The ViewportContainer node’s mouse filter is set to pass. The Viewport’s setting Handle input locally was tested enabled and disabled. The Viewport’s setting Disable input is disabled. The Viewport’s setting Own World was tested enabled and disabled.

Minimal reproduction project:

ViewportIssue.zip

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 10
  • Comments: 31 (9 by maintainers)

Most upvoted comments

I’ve lost about two days with this issue and have finally been able to solve it. What finally clicked for me was wraitii’s comment, in particular:

  • making sure that all upward nodes from the viewport had the mouse_filter set to “Pass”;
  • making sure that physics_object_picking on the viewport was set to true
  • getting rid of the _input and _unhandled_input functions on the viewport parent (a ViewportContainer)
  • adding the following to the parent
func _gui_input(event):
    $Viewport.unhandled_input(event)

I’m not entirely sure this solves the issue, it may not for others, but it did for me. @kone9, would you be willing to test that may bullet points above are able to solve the issue for you?

This may not be a very frequent situation, since it requires handling viewports and mouse input, which I suspect is unusual in game development with Godot. But it should be much more well documented regarding the solution. I’d be happy to contribute but I have no clue where to do it. If someone can point me to the right direction I’d write a few lines in the documentation about this.

Still broken. The workaround does not work. _input_event never fires for an CollisionObject2D node in a viewport. Use case example: A “map” renders to a viewport in a viewportContainer. The use of a viewport allows to scroll the map by moving the camera.

This bug (yes, it’s a bug) makes it impossible to select a unit, building, city, etc… by clicking on it.

Investigated this deeper today: For reference, everything is working as designed, only the design is being difficult :p . Assuming a viewport in a container, with object picking on and everything correctly setup. What happens:

  1. User clicks in the viewport somewhere.
  2. the input is propagated upwards. Here lies the first blocker -> most likely a control will have mouse.filter ‘stop’ then, and things stop here.
  3. If the event wasn’t stopped or handled, the viewport unhandled_input will be called.
  4. Only then does it create a deferred physics picking call.
  5. The deferred physics picking call triggers the collision Objects ‘InputEvent’, sending signals.

This has several flaws:

  • If you want to actually trigger the object picking, you generally need to manually trigger ‘unhandled input’ (as here), as there’s basically always a node with a “stop” mouse filter.
  • Because the physics picking pass is async, input cannot be blocked by picking.
  • It also means that one cannot get a ‘nothing was picked’ input event easily.

So if you have a viewport with some items, and you’d want clicking somewhere on the viewport but not on an item to trigger something, the only solution is to have another area behind those objects (from the camera POV) that gets picked. And when that happens, you can do things (possibly send an input event ‘behind’ for example).

I have to say, because object picking happens during physics processing, I can’t see an easy fix to this (not a godot dev though, so perhaps you guys have an idea already). Perhaps with object picking activated, viewports should ‘hold’ events for at least one physics-processing-frame, and then only bubble them upwards if nothing was picked. This would introduce some slight input lag, but it would make the whole architecture much more predictable, ad you’d either get an object pick event, or a regular GUI input.

EDIT: also for the record, I think it’s better to do hack the viewport container over the viewport, otherwise all inputs go through the viewport, meaning even clicks outside the viewport-container area can trigger picking. So do this instead in the ViewportContainer script:

func _gui_input(event):
	get_node('Viewport').unhandled_input(event)

That is expected behavior. Picking works with unhandled events and currently ViewportContainer pass to its Viewport as unhandled events only those really unhandled in the whole scene.

You need something like this in your Viewport:

extends Viewport

func _input(event):
	unhandled_input(event)

I’ll send a PR that allows to have that working automatically, but I don’t think it will do it into 3.1.0.

Just faced the same problem, but instead of a viewport it was a Panel node that wasn’t propagating the signal to an Area2D node (not child of panel) BELOW (in the common parent tree), the unhandled_input trick solved it (indicating that it inherits the same problem from the viewport).

edit: noted it’s not working properly since now each processed frame the mouse_entered and mouse_exited signals are emited (because the mouse location input may come as a new each frame now) instead of happening a single time in the occurred events

edit2: Input page says the Following :

  1. If no one wanted the event so far, and a Camera is assigned to the Viewport, a ray to the physics world (in the ray direction from the click) will be cast. If this ray hits an object, it will call the CollisionObject._input_event() function in the relevant physics object (bodies receive this callback by default, but areas do not. This can be configured through Area properties).

however I can’t find any properties Area related to activate this callback reception.

邮件已查收~ ( ^o^ ) つロ 乾杯~

It’s working with current head : 59b69500 ViewportContainer must have mouse_filter set to IGNORE Viewport must have Physics : Object Picking ticked

I had the same issue with an Area3D node but none of the suggested workarounds have worked for me. I have a a ViewportContainer with a Viewport child, and the Viewport has a child of a MeshInstance which has a camera setup and some nodes (Area3D) that I want to check if the user clicks on. Using the input_event() function for the Area node works fine if I’m looking at the 3D node, but when I display the 3D scene on a 2D scene using a viewport, this no longer works.

I will add my voice that this seems like a bug or at the least like a very unintuitive issue. There’s no reason why a Viewport would be handling input events for children nodes if the ViewportContainer has its mouse_filter set to ignore. It makes even less sense that it does not appear to be handling events going to control nodes, but only stuff going towards Area2D/CollisionShape2D. So having a mouse_entered() signal on a Panel will work, but the mouse_entered() signal on an Area2D parent of the same panel will not work.

Even more frustratingly, I don’t understand how changing the _input to an _unhandled_input on the viewport script would help. The _input event is anyway received by the Area2D and CollisionShape2D node inside the viewport, it just doesn’t trigger the relevant mouse signals of the CollisionShape2D. One would have to manually recreate the mouse signal logic by hand inside the _input(), no?

It’s a little hack but it helped me.

func _input(ev) -> void:
	
	get_viewport().unhandled_input(ev)

It seems that all signals from CollisionObject2D are affected, because the signal input_event is also not called in the viewport instance.

This is a duplicate of #17326.

2020 and still the same problem https://youtu.be/gp-qCWfLgNU