How do I await a signal that goes through a signal bus? Maybe I am using the wrong way to do this, but I have a node that talks to a global signal bus and tells it some things about dialogue, and then there is another node that is supposed to take the dialogue and say it, but I have to await it because it just ignores the time it takes and continues executing a method. The problem is that it doesn’t let me await and gives me this “Trying to get a return value of a method that returns ‘void’” error. The strange thing is, if I make the dialogue speaker emit the signal locally, it works just fine and I can await it. Any reason that it does this?
Can you post the script and point out the problematic line? There shouldn’t be any difference in signals global or otherwise. It sounds like the method being called either doesn’t have a delay and cannot be awaited, or something is trying to be set to a void function’s return value.
Emitting signals is a void function, there isn’t anything to await on; it’s firing it into the ether. Maybe you want a more tightly coupled speak function
I would agree going up the tree with $"../" is bad, @export is great for handling “up the tree” situations. I also believe signal busses are a bad practice, less global signals the better.
Why do you need it to call from anywhere? I figure “say” should be called on the few things that can talk, they could put their words on an Autoloaded dialogue scene, then everything is on a closed loop and only loaded once.
First thing I think of is using area. I’ll demonstrate how I believe a press “e” to talk could work
extends Area2D
@export var talker: Talker
@onready var label: Label = $Label
func _on_body_entered(body: Node2D) -> void:
if body is Player:
set_process_input(true)
label.show()
func _on_body_exited(body: Node2D) -> void:
if body is Player:
set_process_input(false)
label.hide()
func _input(event: InputEvent) -> void:
if event.is_action_pressed("Interact"):
talker.start_dialogue()
# don't take input again until dialogue is over.
set_process_input(false)
# if dialogue is handled by a Autoloaded scene
await DialogueUI.dialogue_ended
# if dialogue is handled as part of the talker's UI
await talker.dialogue_ended
set_process_input(true)
And in this world here’s how that Talker script would look
extends Node2D
class_name Talker
# again if no Autoloaded dialogue scene
signal dialogue_ended
func start_dialogue():
pass # say a word until dialoge end
I can’t really give specifics without some specific code to adapt to, but I think we’re getting into the weeds of it anyways. The main thing to consider is using a start_dialogue function on whatever object stores talking data; usually whomever is speaking, or it’s data in the level.