Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Area2D mouse_entered and mouse_exited signals not called in Viewport #26181

Closed
Tracked by #45334
BeayemX opened this issue Feb 23, 2019 · 31 comments
Closed
Tracked by #45334

Area2D mouse_entered and mouse_exited signals not called in Viewport #26181

BeayemX opened this issue Feb 23, 2019 · 31 comments

Comments

@BeayemX
Copy link
Contributor

BeayemX commented Feb 23, 2019

Godot version:

Tested with 4f697f7

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

@BeayemX BeayemX changed the title Area2D enter and exit signals not called in Viewport Area2D mouse_entered and mouse_exited signals not called in Viewport Feb 23, 2019
@BeayemX
Copy link
Contributor Author

BeayemX commented Feb 24, 2019

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

@RandomShaper
Copy link
Member

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.

@RandomShaper RandomShaper added this to the 3.1 milestone Mar 9, 2019
@cobreen
Copy link

cobreen commented Jun 10, 2019

I'm using the latest version. It's still not working

@giulianob
Copy link
Contributor

@RandomShaper can we reopen the issue to track it? I just ran into the same issue and it doesnt seem obvious as to the end user why this would not work.

@Skaruts
Copy link

Skaruts commented Jul 29, 2019

@giulianob indeed. It took me a lot of asking around for a problem that had no obvious solution, until I figured this ought to be an issue. In my case it involves 3D Areas.

Thanks for that workaround @RandomShaper.

@Zylann
Copy link
Contributor

Zylann commented Aug 6, 2019

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

@RandomShaper I don't understand, in your example code you used _input, but this is not unhandled events, it's going to catch them all, even when you didn't actually click on the viewport, isn't it?

Also, if I click an Area2D inside a viewport, and the area doesn't react, what exactly is handling that input? And how to make sure it gets forwarded to that viewport and not to some other random script in the game that might have _unhandled_input? Because if input is unhandled so far in the enclosing scene, it might become handled after being checked by objects inside the viewport, and in such case, should not trigger _unhandled_input in the enclosing one.

@Skaruts
Copy link

Skaruts commented Aug 6, 2019

@Zylann , I did have to turn input on/off manually for the viewport, using mouse_entered/exited signals on the parent control, or else it would still receive it while the mouse was over the UI around it.

I suppose this is also related to your other concern, since the input I'm using in the scene that's under the viewport is actually Area input_event signals (for mouse clicks and movement), which according to the docs is neither _input nor _unhandled_input and would normally be handled last.

@cjhorton
Copy link

@Zylann , I did have to turn input on/off manually for the viewport, using mouse_entered/exited signals on the parent control, or else it would still receive it while the mouse was over the UI around it.

I suppose this is also related to your other concern, since the input I'm using in the scene that's under the viewport is actually Area input_event signals (for mouse clicks and movement), which according to the docs is neither _input nor _unhandled_input and would normally be handled last.

I still can't get it to work. I tried the workaround and v3.2 alpha (someone else had mentioned that it was working in it). Perhaps I am not setting it up correctly?

@OlexiyKravchuk
Copy link

It's a little hack but it helped me.

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

@starwolfy
Copy link

starwolfy commented Nov 16, 2019

I still cannot get mouse_entered/exited signals to fire either inside a viewport of a viewportcontainer.

Edit:
I fixed my case. I had to change the area2d to be the child of a newly created control node. Then use the mouse enter and exit events of that control node instead.

@akien-mga akien-mga modified the milestones: 3.2, 4.0 Dec 13, 2019
@wraitii
Copy link

wraitii commented Dec 15, 2019

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)

@konsvasi
Copy link

I've got a similar issue with the latest version 3.2.1.stable.official of Godot, I tried the hack with the unhandled_input and it worked but now the mouse_exited signal is triggered all the time, even when I'm within the Area2D the mouse_exited event is fired all the time.

@anders-s
Copy link

Same issue on 3.2. Connecting the mouse_entered signal from an Area2D to a script never fires that script function. Worked around the same way @nikitaab20 did. Could be my fault, I'm new to Godot.

@luisfmnunes
Copy link

luisfmnunes commented Apr 23, 2020

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.

@Duehok
Copy link

Duehok commented Aug 20, 2020

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.

@db0
Copy link

db0 commented Nov 8, 2020

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?

@kone9
Copy link

kone9 commented Nov 22, 2020

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

@jdferreira
Copy link

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.

@Calinou
Copy link
Member

Calinou commented Jan 18, 2021

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.

See Contributing to the Class Reference with Git 🙂

You want to modify doc/classes/Viewport.xml in the 3.2 branch (not master).

@mg979
Copy link

mg979 commented Feb 21, 2021

I also had the same issue and got it fixed thanks to #26181 (comment).

And what @jdferreira said in #26181 (comment) is also important.

My issue was in a 3d viewport. All this meant to me that as soon as you use a viewport, handling inputs in it becomes impossible if you don't know what's going on, that is if you don't read this issue. I don't have enough knowledge about this stuff, but it seems to me that a viewport container should forward automatically unhandled inputs to a child viewport, what's the point of blocking them?

@DoubleF3lix
Copy link

DoubleF3lix commented Mar 6, 2021

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.

@DoubleF3lix
Copy link

DoubleF3lix commented Apr 27, 2021

After about 3 months of struggling with this on and off, jdferreira's fix worked for me. Mainly, make sure "Object Picking" under "Physics" in your viewport is checked. I had the rest of the system setup, and now it works fine.

@jeremyz
Copy link
Contributor

jeremyz commented May 23, 2021

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

@gilzoide
Copy link

but it seems to me that a viewport container should forward automatically unhandled inputs to a child viewport, what's the point of blocking them?

I totally agree. Inputs could even only be propagated when Viewport.physics_object_picking is true.

This may not be a usual situation in games, but I'd guess it is for desktop/web tools with mouse input.
I'm always seeing more and more tools made with Godot (which is awesome!).

@jeremyz
Copy link
Contributor

jeremyz commented May 25, 2021

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.

It found a work around, prioritizing units Area2d over map Area2D boardgame-map

@nikolamalesevic
Copy link

* adding the following to the parent

@jdferreira Can you please explain which node do you refer to as parent? The parent of the Viewport - ViewportContainer?
I tried following your approach, but to no avail - I still cannot make any mouse picking to work in my viewport (apart on gui elements).

@colorworlds
Copy link

Hello,I have a similar problem.
Then I set following setting:

ViewportContainer must have mouse_filter set to IGNORE
Viewport must have Physics : Object Picking ticked

It worked well on PC.
But When I export to Android, It failed again. Inputs become unresponsive.
I use v3.3.2.stable.offical on win7.
I think it may be caused by ignoring the touch screen event ? I'm not sure

@Skaruts
Copy link

Skaruts commented Oct 22, 2021

To make @RandomShaper's workaround more clear: I've been using this setup for a while, and so far it seems to work fine for me.

This is the scene tree:

ViewportContainer
    Viewport
        Scene (Spatial in my case, but it's probably the same in 2D)

I have a script on the ViewportContainer and another on the Viewport. Then I connect mouse_entered and mouse_exited signals from the ViewportContainer to itself (or to a parent node -- adjust the path to the viewport as needed), and I use them to turn on/off the viewport's input handling:

extends ViewportContainer 

onready var viewport = $Viewport

func _on_ViewportContainer_mouse_entered() -> void:
	viewport.set_process_input(true)

func _on_ViewportContainer_mouse_exited() -> void:
	viewport.set_process_input(false)

(To be honest, at this point I can't quite remember if the code above is strictly needed. Still, one other issue that it solved for me, was that it prevents input from happening at all in the viewport when I'm using other parts of my app, which in my case is what I want.)

And then on the viewport I relay the input as @RandomShaper suggested, but only if it's mouse input. This is because keyboard input seems to go through on its own, and doesn't need to be relayed here. I found this when I noticed my event.is_action_pressed() were being fired twice.

extends Viewport

func _input(event: InputEvent) -> void:
	if event is InputEventMouse:
		unhandled_input(event)

There may be other kinds of input events that need to be relayed too, but I only know about mouse events.

@jamie-pate
Copy link
Contributor

jamie-pate commented Dec 18, 2021

This seems to work without the workaround if you set $ViewportContainer.mouse_filter = ignore

ViewportContainer -> Viewport -> Area.input_event signals will fire.

Feels backwards but it makes sense if you read the thread :D

@colorworlds
Copy link

colorworlds commented Dec 18, 2021 via email

@Sauermann
Copy link
Contributor

This is a duplicate of #17326.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests