+1 vote

Hello,
I have different Area2Ds spawning in my scene and I want to detect when they get clicked. Actually I'm using the following script:

func _input_event(viewport, event, shape_idx):
    if event.type == InputEvent.MOUSE_BUTTON \
    and event.button_index == BUTTON_LEFT \
    and event.pressed: clicked()

However if I have two Area2Ds overlapping, the two will detect the click. So does anyone have a good method to detect the click only on a "visible" object?

Thank you.

BTW here's the actual scenario in my game:

EXAMPLE

in Engine by (16 points)
edited by

I've had this issue as well and I've yet to find an elegant solution. I've tried "setinputas_handled" without success. The best I've come up with is to use a boolean flag as a workaround. I test each object in order of importance for input. The first valid object sets the flag and completes its task. Subsequent objects check and see that the flag is set, and ignore the click. It's not pretty but it works. I'd love to hear a neater solution, or better yet, have a Godot implemented "pickable only if visible" option for the Area2D node.

I don't think that your method will work because I'm instancing the objects. But thank you anyway

1 Answer

+1 vote
Best answer

You can mark an input event as "handled" so it doesn't trigger anything else by calling

SceneTree.set_input_as_handled()

from within your input function.

This only works if you only ask for unhandled input though (using "_unhandled_input") instead of asking for all input (which "_input" does).

One thing you have to be wary of is that you only call "SceneTree.set_input_as_handled()" whenever you're sure that the mouse is currently over the current Area2D, otherwise the frontmost Area2D object will just eat all input events. An easy way to check this is by using the "mouse_enter" and "mouse_exit" signals.

Here's a script that should do exactly this (Godot 2.1.X using GDScript):

extends Area2D

# Whether or not the mouse is currently over this Area2D
var mouse_over = false

func _ready():
    # Connect the signals used to detect if the mouse is hovering
       over the current Area2D
    connect("mouse_enter", self, "_mouse_over", [true])
    connect("mouse_exit",  self, "_mouse_over", [false])

func _unhandled_input(event):
    if mouse_over and event.type == InputEvent.MOUSE_BUTTON
            and event.button_index == BUTTON_LEFT and event.pressed:
        SceneTree.set_input_as_handled() # Mark the current input
                                            event as "handled"
        clicked()

func _mouse_over(over):
    self.mouse_over = over

For Godot 3.0.0 you have to change _ready and _unhandled_input as follows (also using GDScript):

func _ready():
    connect("mouse_entered", self, "_mouse_over", [true])
    connect("mouse_exited",  self, "_mouse_over", [false])

func _unhandled_input(event):
    if mouse_over and event is InputEventMouseButton
            and event.button_index == BUTTON_LEFT and event.is_pressed():
        get_tree().set_input_as_handled()
        clicked()
by (74 points)
edited by

It wasn't working but I fixed it, the code should be the following:

https://pastebin.com/vrDWKUsD

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.