Novice Programmer Seeks Signal Help

Godot Version

4.3

Question

Hello everyone, novice programmer here trying to make a fun game. I’m having an issue regarding signals and how they are added to instantiated scenes. Basically I have a ui panel that displays variables (health, lvl, etc) that gets pushed from a signal from my warrior unit node. It works when I have the unit in the scene, but when I try to spawn a new one the data isn’t being passed over. I’ve tried emitted the signal in the ready function of the warrior but I’m kind of at a loss. If you could help that would be greatly appreciated!

**Warrior Script:**
extends Node2D

var unit_type = "Warrior"
var level = 1
var health = 20
var attack = 5
var defence = 2
var magic_defence = 2

signal warrior_selected(unit_type: String, level: int, health: int, attack: int, defence: int, magic_defence: int)

func _ready() -> void:
	$ProgressBar.value = health
	pass

func _on_character_body_2d_input_event(viewport: Node, event: InputEvent, shape_idx: int) -> void:
	if event is InputEventMouseButton:
		if Input.is_action_just_pressed("Click"):
			emit_signal("warrior_selected", unit_type, level, health, attack, defence, magic_defence)
			print("This is working ", health)
		pass
	pass # Replace with function body.

**Spawner Script:**
extends Marker2D

var warrior_unit_scene = preload("res://Scenes/warrior_unit.tscn")
var spawn_position = Vector2()

# Called when the node enters the scene tree for the first time.
func _ready() -> void:
	pass # Replace with function body.

# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
	pass

func _on_ui_spawn_warrior() -> void:
	var warrior_instance = warrior_unit_scene.instantiate()
	spawn_position = position
	warrior_instance.position = spawn_position
	get_parent().get_parent().get_node("PlayerUnits").add_child(warrior_instance)
	
	pass # Replace with function body.

**UI Script:**
extends CanvasLayer

signal spawn_warrior

# Called when the node enters the scene tree for the first time.
func _ready() -> void:
	$"../PlayerUnits/WarriorUnit".warrior_selected.connect(update_ui_plate)
	pass # Replace with function body.

# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
	pass

func _on_button_pressed() -> void:
	spawn_warrior.emit()
	pass # Replace with function body.

func update_ui_plate(unit_type, level, health, attack, defence, magic_defence):
	$UnitIdPanel/UnitTypeLabel.text = unit_type
	$UnitIdPanel/UnitLevelLabel.text = "Lvl: " + str(level)
	$UnitIdPanel/UnitHealthLabel.text = str(health)
	$UnitIdPanel/UnitAttackLabel.text = str(attack)
	$UnitIdPanel/UnitDefenceLabel.text = str(defence)
	$UnitIdPanel/UnitMagicDefenceLabel.text = str(magic_defence)
	pass

Thanks!

The newly spawned warrior needs to connect his signals with the listener:

func _on_ui_spawn_warrior() -> void:
	var warrior_instance = warrior_unit_scene.instantiate()
	spawn_position = position
	warrior_instance.position = spawn_position
    warrior_instance.warrior_selected.connect(ui.update_ui_plate)   #<------------
	get_parent().get_parent().get_node("PlayerUnits").add_child(warrior_instance)

Note that you will have to give the spawner access to the UI object or rearrange things a bit.

Oh, I thought the signal that I attached to warrior script would be made whenever an instance of the warrior was made. I’ll give this a try tonight when I’m home. Thanks for the help! What you’re saying makes sense though.