0 votes

Hi all,

I'm testing my first ever custom signal.
In this test, I have it working so when I press 1, 2 or 3 on the keyboard, the speed of my bat changes. This works so that's great.

Now I want it so when the speed changes, a signal is emitted. (I believe I have this part correct). When that signal is emitted, a function is called to change the text of a label.

Except it doesn't. Can anyone offer some advice as to what I've done wrong? This is my first custom signal. Thank you.

#script: gameLevel.gd
extends Node

onready var speedLabelL = get_node("/root/gameLevel/HUD/SpeedL")

signal batSpeedChanged

func _ready():

    if OS.is_debug_build():
        print("debug mode")

    if speedLabelL:
        print("We have a label")
        speedLabelL.connect("batSpeedChanged", self, "updateScoresEtc")

    set_process_input(true)

func _input(event):
    if OS.is_debug_build():
        if Input.is_key_pressed(KEY_1):
            changeBatSpeed(0,1)
        elif Input.is_key_pressed(KEY_2):
            changeBatSpeed(0,2)
        elif Input.is_key_pressed(KEY_3):
            changeBatSpeed(0,3)

func changeBatSpeed(bat, speed):
    if bat == 0: #left bat
        game.batSpeedL = speed
    elif bat == 1: #right bat
        game.batSpeedR = speed

    if OS.is_debug_build():
        print("Bat speed = ", str(speed), " for bat # ", str(bat))

    emit_signal("batSpeedChanged", bat, speed)


func updateScoresEtc(bat, speed):
    if OS.is_debug_build():
        print("signal should happen with bat", str(bat), " and speed of ", str(speed))
        print("This is where we'll change the label text")

Just a note, all the print statements work except for the last one in the updateScoresEtc function.

in Engine by (825 points)
edited by

You should avoid getting nodes outside of the current scene. In your code you are calling get_node("/root..., which only works if there is the correct node at the hardcoded path.
But the main point of using signals is to be able to add a function call in an object before you even know which object is the one containing the function to be called. So your script can change the bat speed and call some function that should be called when the speed changes without knowing which function that is.
If you have a reference to the speed label in your script you can simply call the correct method on the label.

Tl,dr: put both the label and the speed changing object into one scene and have that new scene that owns both objects connect the signal with the label's function.

Thank you. I came to this conclusion last night. Once I resolved the current code I sat and thought about the ways I could use signals. At first I was excited about the opportunities in terms of features (bad guys being spawned. Player collides with an object. Player dies. Bullets fired. Etc). Then I got excited about implementation. The idea that I can write a listener of sorts, attached to an object. Then all I have to do is send the signals, from ANYWHERE and the listener will receive the signal. That's incredible in terms of simplifying code. This game I'm working on (pong) is my third game and if I'd have known about signals properly in the last two games I'd have done them very differently. But, such is the learning process.

2 Answers

+5 votes
Best answer

You should define the signal on the node which emits it. Now it is defined in the listener node.

A simple example would be like this:

Player script

extends Sprite

signal hurt

func _ready():
    pass

func hit_by_sword():
    #the player got attacked
    emit_signal("hurt")

Observer node, ie., some HUD

extends Label

func _ready():
    var player = get_node("path/to/player/node")
    player.connect("hurt",self,"_on_player_hurt")

func _on_player_hurt():
    print('Player got hurt")
by (750 points)
selected by

Thank you! That works perfectly. I had no idea that you couldn't emit and receive a signal in the one script file. I have it working now.

+1 vote

I had no idea that you couldn't emit and receive a signal in the one
script file.

You can. Though the intention of signals are to allow you to decouple classes. So they don't have direct dependencies. They just listen for a signal, they don't care who does it or how it gets done. So if it's all code inside the same object, it's hard to imagine a case why you wouldn't just directly perform the function or actions you want done.

I tested your code, and as far as I can tell your signal code works just fine. If there are issues with the label your bug may be elsewhere.

by (5,240 points)

There must have been another issue yes. Since moving it though I've corrected whatever it was which worked out but at least I understand them better now. You're right, why use a signal in the same script when you can just reference a function. Silly. But, it's starting to make sense so thank you.

You're welcome.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.