How to detect mouse click on top most layer

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Noe
:warning: Old Version Published before Godot 3 was released.

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

I’ve had this issue as well and I’ve yet to find an elegant solution. I’ve tried “set_input_as_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.

Michael Paul | 2017-10-26 10:45

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

Noe | 2017-10-26 15:35

:bust_in_silhouette: Reply From: Robin Arys

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()

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

extends Area2D# Whether or not the mouse is currently over this Area2Dvar - Pastebin.com

Noe | 2017-10-27 10:13