Help properly connecting a signal

Godot Version

4.2 Stable

Question

I’m writing a turn based combat system and want to use signals to communicate between an autoloaded singleton named BattleManager and as many “character” nodes in the battle scene.

I’ve created a signal in BattleManager called roll_initiative and emit in my _ready function. Code for the BattleManager.gd:

extends Node
var turn_manager
signal roll_initiative
signal recieve_initiative
signal attack_turn 
signal apply_ability
# Called when the node enters the scene tree for the first time.
func _ready():
	print("sent initiative roll signal")
	roll_initiative.emit()
	
func _process(_delta):
	pass

as expected, the print message comes out in the output log but my character node which should respond to roll_initiative.emit() doesn’t even print anything after I verified that the signal is being emitted. Here’s the character node that should connect to the roll_initiative signal:

extends CharacterBody3D

@export var health: int = 25
@export var attack: int = 10
@export var defense: int = 10
@export var magic: int = 10

signal initiative_rolled

func _ready():
	print("hello!")
	var battle_manager = get_node("/root/BattleManager")
	battle_manager.roll_initiative.connect(_on_battle_manager_roll_initiative)

func _process(delta):
	pass


func _on_battle_manager_roll_initiative():
	var rng = RandomNumberGenerator.new()
	print(self.name," rolled a: ",rng.randi_range(1,20))
	print("got it!")	

Please guide me in the right direction :slight_smile:

Probably the singleton/autoload is ready before CharacterBody.

I’d swap the singleton to a Node, or force the signal somewhere else and try that way just to test.

Anyways, if it is a autoload/singleton you should be able to use it Globally, simply by saying BattleManager.roll_initiative.connect(_on_battle_manager_roll_initiative) instead of var battle_manager = get_node("/root/BattleManager") and then calling it.

edit:

when I try setting the battlemanager to a node
var battlemanager = get_node("BattleManager") battlemanager.roll_initiative.connect(_on_battle_manager_roll_initiative)

I get the error:
character.gd:11 @ _ready(): Node not found: "BattleManager" (relative to "/root/Battle/ProtagGroup/Character").

This is the scene tree that the BattleManager and character nodes are located:
image

ProtagGroup is just a group of characters

So I replicated this, and indeed, what is happening is what I said before:

So, this is what the current code looks like:

BattleManager:

# Called when the node enters the scene tree for the first time.
func _ready():
	print("BATTLE_MANAGER LOADED")

## This function is the one that emits the signal.
# It is being encapsulated because 
# now you have to consider who would call on this function
# plus, you would want more events happening inside.
func roll() -> void:
	roll_initiative.emit()
	pass
#I personally add pass at the end of functions so I can see better where it ends.

Character:

func _ready():
	print("CHARACTER LOADED")
	
	BattleManager.roll_initiative.connect(_on_battle_manager_roll_initiative)
	
	""" 
	Handle carefully, I mean. Again. 
	Who should call on the function to roll?
	"""
	# Once roll is called, any connected signal will trigger.
	BattleManager.roll()
	pass


# Now the call is complete, and you can see it action
func _on_battle_manager_roll_initiative():
	var rng = RandomNumberGenerator.new()
	print(self.name," rolled a: ",rng.randi_range(1,20))
	print("got it!")
	pass

The test itself:
image

1 Like

To simply fix this, then do as you did here:

Expose the variable to the inspector by writing @export var battle_manager inside CharacterBody3D.

Then, drag and drop the node into the now exposed field!

1 Like

that’ll do it! Thanks again, I think my base understanding on signals isn’t great so I’ve got some stuff to work on. You rock!

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.