Victor Aruya
Victor Aruya

Reputation: 1

Input affects both sprite infront and behind it in Godot

I have two scenes in Godot, one for the game scene and one with a sprite, the sprite is going to spawn into the game scene at random, the player will have to click the sprite when it spawns into the game scene once the sprite is clicked it disappears and the player gets one point, but if the player clickes the background it is game over and a game over scene pops up, the problem is when the sprite is clicked it also affects the background collision, I have been trying forever to fix this collision layers and masks doesn't solve the problem please what should I do(I use gdscript).

I tried putting the sprite and background in different layers, I also tried putting them in different groups, but none of them worked.

Upvotes: 0

Views: 885

Answers (1)

hubfix
hubfix

Reputation: 51

As the question is presented I assume that you are talking about "collisions" as it is the mechanism you are using to detect clicks, since the scenario you described doesn't specify if collisions are actually required as a gameplay mechanic to let Sprites interact between or with other entities.
Also you didn't specify if you want to achieve it on Godot 3 or 4, so I'll assume you are going for Godot 3 even though my next suggestions will work on 4 too. If that's the case:

  • Suggestion 1: don't rely on collision and collision shapes to manage user interactions such as clicks. Generally speaking, if you only need to detect a click, leave everything related to physics alone as you don't really need it and will just make everything a little more hard to handle and less performant.
    All Nodes inheriting classes including Sprite2D have a builtin _input(event: InputEvent) method which you can override to detect any input. For clicks on desktop platform, you will specifically be looking for the InputEventMouseButton which detects clicks. To detect clicks, something like this should work:
class Sprite2D

func _input(event: InputEvent) -> void:

    if event is InputEventMouseButton and not event.pressed:
        print("Mouse button released on position %s" % event.global_position)
        get_tree().set_input_as_handled()

The event is captured directly on a specific Sprite2D which means it was clicked. In this case, unless you need it, you don't have to check for the position of the event.
The _input() function is the first one to be called in the stack as described in the docs.
What happens in your case is that the input propagates after you receive it on your Sprite2D, and propagation happens from going up in the Tree (so exactly as you mentioned, from the Sprite to your Background). That's why I've added the line get_tree().set_input_as_handled(). It will explicitly tell the engine that the InputEvent you received has been consumed and shouldn't be propagated anymore.
About the not event.pressed condition: as you can read from the documentation, event.pressed identifies if the mouse button (whatever it is since we are not specifying which one through the event.button_index property) is being pressed. When released event.pressed is false, hence it is a good practice to detect clicks on released buttons instead of pressed (because you are sure that the user "clicked" instead of "dragging", which could be associated to another mechanic in your game).

This is more than enough and should suit your case. However, you can always handle things differently based on the level of complexity you want to add in your Tree and how you want to handle your logic:

  • Suggestion 2: user Area2D nodes instead of Collisions to detect mouse events. Using signals and Area2D the input should be automatically consumed by the engine so no propagation will happen.

Hope the answer helped you, I've made a few assumptions as your question was very generic.

Upvotes: 1

Related Questions