Sending signals between scene nodes

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By RazorSh4rk

(I searched for similar questions but didn’t find anything that would be too similar, but if you know any pointers, please link them.)

The problem:
I have a Player and a Door scene (the game is 2D) .What I want to do, is when the Player collides with the Door (this part is ok) and the player presses a button, the Door should play an animation. I tried with

  • The Door.gd detects the button press and collision and plays the animation. The problem here is that the player has to do a ton of other stuff to hide inside (think Outlast), so that’s a lot of code.
  • The player detects button press and makes the Door play the animation. This is working, but only by
func _on_ColliderL_body_entered(body):
	(body.get_parent().get_children())[0].play("open")

Which is… yeah, ugly and Godot is smarter than this.

Now the question is, assume I want to keep Player and Door in separate scenes and want to reuse them in different levels (with always more than 1 door on a level). Is there a way to send a generic signal to another scene, or is there a better way of doing this?

Big scene (level) structure is

  • Node2D
    → Player
    → //misc nodes
    → Door0
    → Door1

Have you tried setting one of your nodes (the player node or the door node) to use the emit_signal function? You may be able to program it such that the interested nodes are listening to that exact signal. If you haven’t seen it, here’s some more information on emitting a signal (it’s at the bottom of the section).

Ertain | 2018-12-12 21:48

:bust_in_silhouette: Reply From: rojekabc

Want be easier, if you detects a collision not on side of player, but on side of door? Than you may check, that collider is a player and then execute your action.

Create separate scenes is a normal way. You may send signals between them, but sending signal directly to an instance of selected scene make no sense - you may just call a function inside it.

:bust_in_silhouette: Reply From: RazorSh4rk

Reading the suggestions and diving into the docs i think i figured out an okay method

#Player.gd
signal _hide
...
emit_signal('_hide')

#Door.gd
func _ready():
   get_parent().get_child(0).connect('_hide', self, '_hide')

func _hide():
   $AnimatedSprite.play('open')

Setting the player as the first child makes sense (at least to me, anyways)