How can I connect a signal if I don't know the path to the emmiter object/node?

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

Hi all,

I am still struggling with this. I know it will “click” at some point so I’m hoping this is that moment.

I am building a breakout / arkanoid clone.

I have many brick nodes on screen.
When the ball hits the bricks, they explode.
I want to know what texture the brick contains, so the particles can use that to their advantage.

So in my brick.gd scene I have:

var currentTexture = get_node("TextureButton").get_normal_texture()
var currentTextureName = currentTexture.get_path()
emit_signal("brickColour", currentTextureName)

In my particle scene I have:

func _ready():
    connect("brickColour", self, "setParticleTexture")

func setParticleTexture(colour):
	print ("texture is : ", colour)

The problem is that Print statement never occurs. Nothing is being sent (or received at least).

Now I KNOW that in my particle scene I need to have something like:

func _ready():
	var brick = get_node("/path/to/brick")
    brick.connect("brickColour", self, "setParticleTexture")

BUT I don’t know what that path is to each brick as there are HEAPS of bricks and they are named in various strange names that have been assigned to them. So I can’t know what bricks name it was, that sent the signal.

How can I get around this? There MUST be a way, I just can’t wrap my head around it.

Any help would be very much appreciated.

Are the particles spawned from the bricks? You don’t need signals for that, just set the texture directly to the instance of the particle, like:

var particle = particle_class.new()
particle.set_texture(load(texture_path))
# add the particle to the scene

If the particle is a Sprite node, that is. Otherwise you would create a variable called texture_path in the particle and set the sprite texture to that value on ready:

var texture_path = ""

func _ready():
    get_node("sprite").set_texture(load(texture_path))

And in the spawn code:

# ...
particle.texture_path = texture_path
# add particle to the scene

manokara | 2017-07-26 05:03

Hey there, thanks for replying.

The particles are in another scene that is instanced when required (when a ball hits a brick). I want to keep it that way as they have other things they do and I like it being separate.

If I can figure out how to get the signals to work then I can keep that separation of scenes.

Robster | 2017-07-26 05:59

Presumably, at some point you know the position where the collision occured and pass that along to whatever code spawns the particle scene. In order to set the position of the particles.

Assuming that, wouldn’t you also be able to get the brick involved in the collision, determine its color and pass that information to the particle scene, along with the position?

You wouldn’t need to use signals at all in that case.


If you really do need to use signals, maybe it would be better to connect to a central node that emits the needed signals…

One that can be easily reached from all nodes that need to communicate… say the level itself, or a singleton.

Then at the point where the brick emits the signal, have that central node emit the signal instead.

aozasori | 2017-07-26 13:42

:bust_in_silhouette: Reply From: RandomShaper

You can add the receivers to a group and “notify” them with get_tree().call_group() with the right parameters.

That should only be used as a last resort, because it uses global variables (the groups), which is bad because it makes it harder to reuse code.

Warlaan | 2017-07-27 20:43

This is game development or, more precisely, game scripting. Here you don’t need to worry about design patterns and code reuse as much as in other kinds of development. Of course, you have to embrace good practices, but sacrifying an useful feature of the engine, suited for the task, won’t pay here.

Anyway, using groups, on the contrary, favor less coupling and less amount of elements to manage, which improves maintainability.

The OP was looking for some mechanism of sending messages between objects with bo prior knowledge of the exact setup, and group calls are the answer. I find them to be a good fit for this case, not to be used everywhere.

Maybe I’m missing exactly what your concerns are. If I haven’t convinced you, please develop your arguments further so we can understand each other’s point of view better.

RandomShaper | 2017-07-27 21:37

:bust_in_silhouette: Reply From: Warlaan

Unlike other engines Godot promotes using aggregates rather than components. That means that one object should not need to know anything about other objects besides the ones it is made of.

If you were to connect the signal emitted from a brick in the particle you would be breaking this principle. Instead you should be using signals as if you were hooking up a DVD player to your TV:

Both the TV and the DVD player were built without knowing anything about the other device. That works because the DVD player emits a signal that can be received by the TV. Both the DVD player and the TV still work when the signal is not forwarded to the TV, they just aren’t connected.
Now who needs to connect the two devices? Obviously their owner.

Just like that you should connect signals in the scene that owns both the sender and the receiver. So instead of accessing the brick from the particle scene access both the brick and the particle from the surrounding scene, because that’s the only scene that is allowed to know that both of them exist and which path they have.

Otherwise if you were to move the bricks inside the surrounding scene you would have to modify the particle scene accordingly. If you do it the way I just described the path of the bricks and the code that uses that path is both part of the same scene, and changing one scene can’t break an other scene.

Your idea is good from an engineering standpoint, but don’t you think it’s a bit overkill?

Group calls isolate components even better. If you were to use an element from a game in another (pretty weird) or in a different level setup, groups would be part of the de-facto public API, just like signals.

RandomShaper | 2017-07-27 21:43