#How to connect a signal from an instantiated entity?

1 messages · Page 1 of 1 (latest)

stuck forge
#

I have a monster, and within the monster script I have a node. The node3d emits a signal to tell my monster script that it is dead. I want to connect, or be able to communicate the dead signal to a script that is instantiating the monster, but I do not know how to get a signal from it... any way to solve this?:


@export var spawn_points : Array[Node3D] = []

@onready var ROBOT_MONSTER = preload("res://characters/enemies/robot_monster/robot_monster.tscn")

@onready var rand = RandomNumberGenerator.new()

var current_wave = 0
var dead_enemies = 0
var monster_dict = {
    1:5,
    2:8,
    3:10,
    4:15,
    5:18,
}

func _ready():
    pass
#
func on_enemy_dead():
    if dead_enemies == monster_dict[current_wave]:
        $Wave_Break_Timer.start()
        WaveManager.enemy_dead = 0

func spawn_enemies():
    for i in range(monster_dict[current_wave]):
        var m = ROBOT_MONSTER.instantiate()
        print("spawning %s enemies" % [monster_dict[current_wave]])
        var spawn_length = spawn_points.size()
        var rand_spawn = rand.randi_range(0, spawn_length)
        var spawn_pos = $SpawnPoints.get_child(rand_spawn).position
        m.position = spawn_pos
        add_child(m)
        await get_tree().create_timer(2.0).timeout.connect(spawn_enemies)```
proven storm
#

simplest way would be to loop through the children in the node. You can give them a group to make it easier to define what your looking for.

stuck forge
#

The enemies are in the group "enemy"
But I don't know how I can loop through the nodes efficiently unless I run the function in process

twilit kayak
#

If I'm remembering what I did correctly, I believe I had the instantiated entity set it up.

One of my iterations gave the signal emitter a function like setupEmitters(Enemy enemy) which the enemy would call, and the emitter would set up the enemy.

I'm not sure that was a great solution, but it did get the job done.

I'm pretty sure I spent quite a bit of time rewriting that code. I'll see if I can find it while the slowdown runs.

twilit kayak
#

Here are the things I have found that I do. Note that my code is in C#, and I'd have to do some work to translate this into GD Script.

  • Set up signals during construction of the object, taking advantage of the fact that the parent currently holds a reference:

meh example because I'm modifying a found child, but this method should work with instantiating children as well.

    public override void _Ready()
    {
        if (_meshChild == null)
        {
            _meshChild = new MeshInstance3D()
            {
                Mesh = _mesh
            };
        }
        if (Engine.IsEditorHint())
        {
            return;
        }
        
        if (location == null)
        {
            location = GetParent<area>();
        }
        var child = GetNode<StaticBody3D>("body");
        child.AddChild(_meshChild);
        child.MouseEntered += this.hoverStart;
        child.MouseExited += this.hoverStop;
        child.InputEvent += this.connectorTest;
    }
  • Signal hubs. I don't think I currently have any dedicated in my code, but the idea is that you listen and signal from the hub. If everything is public, I think objects can set themselves up with a listener, though you will need functions to allow children to tell the emitter to emit. (Weird quirk, I guess?) .

  • Putting the signals and emitters on the class rather than the instantiated objects, making the class into a signal hub.

====

stuck forge
#

I just now solved it after you sent that LOL:

    for i in range(monster_dict[current_wave]):
        var m = ROBOT_MONSTER.instantiate()
        print("spawning %s enemies" % [monster_dict[current_wave]])
        var spawn_length = spawn_points.size()
        var rand_spawn = rand.randi_range(0, spawn_length)
        var spawn_pos = $SpawnPoints.get_child(rand_spawn).position
        m.position = spawn_pos
        add_child(m)
        
        var health_manager = m.get_node("HealthManager")
        health_manager.connect("died", Callable(on_enemy_dead))
        
        await get_tree().create_timer(2.0).timeout```

I referenced the child node and then connected the signal instead of calling the function when they are spawned
twilit kayak
#

Was not ready to send, but

Taking a look at your current design, I'd probably lean towards either the first or third bullet point.

You have a convenient opportunity in your spawn_enemies function to add a listener to your monster's individual signals, which would do what you want pretty directly.

The third bullet point I've found is cleaner, but you do have to to communicate the caller

stuck forge
#

Thank you for the help!

#

I appreciate the time you spent searching for the code 👍