Menu
CoddyTech

What is a Signal?

Part of the Object Oriented Programming section of Coddy's GDScript journey. Lesson 35 of 65.

Things happen to objects while a game runs: a coin is collected, a door opens, the hero's hp drops to 0. Other parts of the program react to these events: the score goes up, a sound plays, the game over screen appears.

A signal is a message an object sends when something happens to it. The object emits the signal, and every function connected to that signal runs:

# coin.gd
class_name Coin
extends RefCounted

signal collected

func collect() -> void:
	print("Coin picked up")
	collected.emit()

signal collected declares the signal and collected.emit() sends it. The coin does not know who is listening. The code that cares about coins connects one of its own functions to the signal:

# main.gd
func _ready():
	var coin := Coin.new()
	coin.collected.connect(_on_coin_collected)
	coin.collect()
	print("Done")

func _on_coin_collected() -> void:
	print("Score +1")

The output is Coin picked up, Score +1, Done. Emitting runs the connected functions right away, before the line after emit(). A signal with no connected functions does nothing when it is emitted.

Without a signal, collect() would have to call the score code itself, so every coin would need a reference to the score board. With a signal, the coin only announces the event, and any number of listeners, or none, can react to it.

Godot's own nodes work the same way: a Button emits pressed when it is clicked, and a Timer emits timeout when its time runs out.

challenge icon

Challenge

Easy

A mailbox announces new mail with a signal. Mailbox already declares signal mail_arrived and has a letters counter. Write deliver(kind):

  • When kind is "letter", add 1 to letters and emit mail_arrived.
  • Any other kind (an ad, a flyer) is thrown away: nothing changes and nothing is emitted.

The supplied code connects a function that prints You've got mail!, then reads how many lines follow and delivers each one. The line away disconnects that function and home connects it again, so a letter that arrives while you are away is counted but not announced. For the lines letter, ad, away, letter it prints:

Delivering: letter
You've got mail!
Delivering: ad
Delivering: letter
Letters: 2

Your code goes in mailbox.gd. main.gd holds the supplied input/output code and cannot be edited.

Try it yourself

extends Node

func _ready():
	# Supplied input/output code: keep it as it is
	var mailbox := Mailbox.new()
	mailbox.mail_arrived.connect(_on_mail_arrived)
	var count := int(OS.read_string_from_stdin())
	for i in count:
		var line := OS.read_string_from_stdin()
		if line == "away":
			mailbox.mail_arrived.disconnect(_on_mail_arrived)
		elif line == "home":
			mailbox.mail_arrived.connect(_on_mail_arrived)
		else:
			print("Delivering: ", line)
			mailbox.deliver(line)
	print("Letters: ", mailbox.letters)

func _on_mail_arrived() -> void:
	print("You've got mail!")
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming

Practice on your own: Online GDScript compiler