How to detect click inside StaticBody2D in Godot Game Engine?


A simple approach to detect mouse click in our game is to intercept input event in in-built _input method. Let’s intercept the input.

extends StaticBody2D
func _input(event):
    if event is InputEventMouseButton:
        if event.button_index == BUTTON_LEFT and event.pressed:
            print(“A click!”)

The problem is that input detection is registered all over the viewport. Let me explain. I have a Sprite child node inside StaticBody2D node. My intention is to detect mouse input over the visible sprite only. In our 2D game we may want to select an object in our world with mouse and do some interaction with it. In this case mouse input is been registered outside the Sprite node.Note that our script is attached to StaticBody2D. As a result this node has to have a shape, so the example has a collision shape as a child. We are trying to keep Sprite node loosely coupled from the logic. Documentation clearly says that StaticBody2D is not intended to move. This makes perfect for objects like trees in the game.

Let’s come back to our problem. My assumption for the behaviour would be that StaticBody2D is shapeless. Yes, we did add a collision shape so it mouse input should be triggered only over defined collision shape. However, StaticBody2D is behaving shapeless and mouse input is registered all over the screen.

A simple approach I discovered is two steps.

First, The property of CollisionObject2D called Pickable, more specifically input_pickable

bool input_pickable
If true, this object is pickable. A pickable object can detect the mouse pointer entering/leaving, and if the mouse is inside it, report input events. Requires at least one collision_layer bit to be set.

We set the Pickable to be true.

Second, The method of CollisionObject2D called _input_event.

void _input_event ( Object viewport, InputEvent event, int shape_idx )
Accepts unhandled InputEvents. Requires input_pickable to be true. shape_idx is the child index of the clicked Shape2D. Connect to the input_event signal to easily pick up these events.

Note that we are not talking about previous _input method. The difference between _input and _input_event I could deduce is that later is registered by pickable CollisionObject2D only, whereas former is just triggered whenever change in event occurs.

That’s it. We will solve our problem by using pickable CollisionObject2D.

  • I will position the collision shape (capsule, rectangle, concave polygon etc) over the Sprite where I need to register mouse selection.
  • Set the Pickable to true in the Editor.
  • Implement void _input_event ( Object viewport, InputEvent event, int shape_idx )

extends StaticBody2D

func _input_event(viewport, event, shape_idx):
    if event is InputEventMouseButton:
        if event.button_index == BUTTON_LEFT and event.pressed:
            print("A Click!")

More Articles

Recommended posts