Decouple game objects using Godot signals

Before going further, let me state that this tutorial is intended for absolute beginners who have no idea about signals and finding a hard time following the official documentation.

There are times we need to use some type of notification services. Whether the player hits an enemy or player health reached zero, be it anything, we require other areas of the game to be notified of those. We don’t want to write functions for each and every object and call it from somewhere. It will be so horrible that when you return the next day morning, you will throw your project. In this article, we will look what are Godot signals and how the signals can be used for better separation between game objects.

If you looked into the physics related nodes, you already know a basic idea of how signals work. A RigidBody2D has many signals associated with it.

Since RigidBody2D is inherited, all of its ancestors’ signals are also available. These signals are emitted whenever its related event occurs. For eg, the signal ‘body_enter’ signal is emitted when the RigidBody2D collides with another physics object. If we listen to the signal,

connect("body_enter",self,"_collided_with_something")

func _collided_with_something(otherbody):
    print("Collided with ", otherbody)

whenever it collides with any other object, the function which is passed as the third parameter in the connect API is called. The second parameter denotes where the callback function is defined. Signal callbacks can have arguments so that we get the details of the event. In this condition, we get the other collided body.

Also Read:   Godot Engine ShaderGraph Introduction - Scrolling a texture

Custom Signals

We can create our own signals whenever needed, this helps in creating independent game objects. In our games, we require some type of UI to display the game status. Let us say we need a player health OSD. Let us look two scenarios,

  1. UI update code is written inside the player script and it will call it whenever player health is updated.
  2. Player emits a signal, UI script listens for it and update themselves.

Which one do you think elegant?

If at a later time, we want the player to be in a section where no UI exists, we would want to change the player script to include some condition checking in place. What happens if there are many of these conditions involved?

When signals are used to communicate, other elements can update themselves without depending on any other element. Removing an element or themselves won’t make any problem in our game.

Godot signals for beginners tutorial Click To Tweet

Creating a custom signal

We can define a signal like this on the top of your script where we define variables.

signal playerhurt

Then when player is hurt, we emit the signal

emit_signal("playerhurt")

Now other elements can listen for this signal

player.connect("playerhurt",self,"_on_player_hurt")

From my experience, you should use constants for signals instead of strings. This is to help us with auto completion when our project grows bigger.

const SIGNAL_PLAYER_HURT = "playerhurt"
signal playerhurt

...

func _on_hit_by_arrow():
    emit_signal(SIGNAL_PLAYER_HURT)

And inside other scripts,

player.connect(player.SIGNAL_PLAYER_HURT,self,"_on_player_hurt")

Where can you use signals

Signals can be used wherever we prefer want to separate two objects depending on each other. Common use cases of signals are,

  1. Gameover
  2. Gamewin
  3. Levelup
  4. Levelfailed
  5. Player health update
  6. Collectible pickup
Also Read:   Create a Catch the egg game in Godot engine - 5

Sometimes we forget to add the signals in the editor and waste hours checking why the callbacks are not firing. Adding signals and callbacks purely via code will help in these situations and the script will be portable to other objects without any configuration in the inspector.

Thanks for reading.

Never miss any content from Codetuto!

Subscribe to Codetuto Newsletter and be the first to recieve our latest posts and tutorials

Subscribe Now For Free

[Total: 1    Average: 5/5]