0 votes

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

asked Oct 23, 2017 in Engine by Noe (15 points)
edited Oct 23, 2017 by Noe

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()
answered Oct 26, 2017 by Robin Arys (74 points)
edited Oct 28, 2017 by Robin Arys

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.