How to use Signals in Godot 4.6 - Complete Beginner Guide (Event Bus, Await, Private Signals)
538 segments
Today we're going to cut the cables.
We're going to start with basic button
signals, cover the new GDO 4.6 hidden
signal features, and end by building a
professional event bus, otherwise known
as a signal bus. Welcome back to GDO dev
checkpoint. Today, we're going to tackle
the lifeblood of GDAU architecture,
signals. These signals allow nodes to
send messages that something happened
without caring who's listening. We're
going to build a signal survivor
prototype game. We're going to start
simple. By the end, we will build a
global communication network that
professional indie devs use. First,
let's use the signals GDAU gives us for
free. We need a button to keep our
survivor alive. Now, today we're going
to be using the new release of 4.6. I'll
put the link in the description, but
gdau engine.org you can get this new
version. Now, over here in a blank
project, I'm going to create a control
node scene here. I'll rename this
control node to game. as a child. For
this, I'm going to add a button.
I'm going to set the text to recharge.
Well, I'm going to anchor this button to
the middle. Center. Anchor center.
I'm going to add a another child node.
Label.
Take our caps lock off. There we go. Get
a label. A label text. I'm going to have
it say
energy
zero. I'm also going to center this
anchor. I'm going to use the move tool
here. I'm going to drag it up just a
little bit. Now, with that, I'm going to
add a script to our loot node game. Add
script. I'm just going to call game
create. I'm get rid of this boiler plate
code here. And then I'm going to select
this button right here. Now, we're
coming from older version here. You'll
notice that the new 4.6 six has
reorganized its signals in groups
section here. So now we have signals
instead of node dock tabs a lot more
better organized. Now in our signals tab
here with our button selected we're
going to double click on this pressed
signal here and we're going to attach it
to our game script on button pressed
connect.
And now we have our button pressed
signal connected to our script. And in
here, we're just going to put in a print
statement. I say signal received
recharging.
Okay. And save the scene. Crl S. Save
scene as game. That's fine. And up here,
we're going to F6. We're on current
scene.
Then I'm going to pull this up a little
bit. And we click recharge. We'll see
down here. Single signal received.
Recharging.
I keep doing it. There it goes. Now,
that kind of signal, what we call that
is an editor connection. That's great
for static things that never change like
your main menu buttons or your options
buttons. But for things that we need to
have dynamic, we use code connections
for everything else, especially gameplay
mechanics and spawned objects.
The editor is fine for prototypes, but
in real games, you often spawn things
with code. You need to know how to
connect signals manually. This is going
to be the syntax you'll use probably 90%
of the time. Now, back in our signal
dock here with our button selected,
we're actually going to disconnect this
pressed signal. Right click, disconnect.
Then we're actually delete this
autocompleted signal it put in for us.
Go to save the script. Then what we're
going to do, I come in here and I'm
going to write a function called on
recharge
clicked.
And that's going to be a return avoid.
So it's not going to return anything.
And we're going to print connected
via toad.
I'm going to save that. Then we need a
ready function. Function ready. We'll
let autocomplete with tab enter down.
Now the syntax for the connection that
we want to do through code. Now it's
going to be a syntax is going to be for
example it's going to be the node you
want. It's going to be the signal name
that you want to use and then we want to
connect that to the callable function we
want to connect to it.
For example, this node here, what we're
going to use is we're actually connect
our button node and the signal name
we're going to use is the pressed and
then we're going to connect to our
callable function which is on recharge
clicked. Okay, so all that. So the money
symbol we get our path. Always best to
use autocomplete with this so you don't
accidentally mistype something. So you
money symbol a path will pop up. We'll
select button. Then we want to select
the press here. I'm going to use the
pressed signal. Just type in pressed.
There we go. We want to actually
then connect to it. So connect. So now
we're connect to the pressed signal on
the button. But what do we want to
connect? We want to connect our function
which is on recharge
clicked.
on this part here. I'm going to make
this bigger. We'll zoom in.
Let me get rid of this output real
quick. Now, we're going to stop here.
Before we type this, look at the end of
this function name. We do not need these
parentheses here. Now, this is one of
the a common mistake that beginners can
make. Now, obviously, our editor is
going to yell at us when we do this and
tell us this is not actually good
syntax. But why? Well, if you write the
parentheses here, you're telling GDAU
that it wants this right now. So, when
you write a function name without the
parenthesis, you're giving GDAU the
recipe. So, the column. So, we'll delete
those.
See, our arrow goes away. Now, that GDAU
has the recipe. Say that we're baking a
cake. You're saying, "Hey, here's the
instructions on how to bake that cake.
Please follow them later when this
button is pressed. Now, if you add the
parentheses, you're saying, "Hey, bake
this cake right now, right when the
ready starts, right when the game
starts, not when you click the button."
But since the function doesn't actually
return anything, you're trying to
connect nothing and that will crash the
game. So one thing to remember when we
pass functions into signals and connect
them function name only
no parenthesis allowed.
But with that we're going to save. We'll
make this smaller.
Then let's do a test run with F6 or
click right up here. Now we have our
Hold this up a bit. I'm going to click
recharge. And now we're connected via
code.
There we are. It's connected via code
with our connection not with the editor
but through our code.
We keep clicking it and there we go.
Now, what if we want to shout a message?
We need custom signals. Now, we're going
to make an energy level dropped out. And
so, when it changes, we're going to
broadcast that new value so that we'll
be able to see it on the screen.
We'll make this smaller and make this
bigger. So, the top of this script our
game script. I'm going to write signal
and then the definition of the signal is
going to be energy changed
and what are we going to put in this
energy change? Well, the new amount we
want to pass into it. Now we got a big
change with signals we get 4.6. We have
private signals now. So what this means
if we had a signal without the
underscore
then it is visible and it's public.
Basically, they put an underscore right
before the signal. Well, that makes it
private. So, it should not show up in
your documentation or the class or the
script that you're writing. And it also
should not be in the autocomp
completion. I say should not because
currently this is actually not working.
Now, there was some confusion about the
underscore signals and they're supposed
to hide them in the autocomplete,
but accordingly that is not the case.
It's actually only for the core methods,
but the script methods that does still
hide it in the documentation.
As of now, it does not hide it in your
autocomplete.
Well, back into our script, I'm going to
put an unders in front of energy changed
here. I'm going to save, but it does
work for the documentation. So, for
example, if I write another signal here,
that's energy changed
and it's just new amount.
And then if I go in the documentation
for this, if I look in the docs, we hit
F1.
F1. And then we can search for our
script game.gd
right here. And then if we go into our
script and open it. Now we have our own
doc for our GDScript. You'll see that
our energy changed.
The public one without the underscore is
here. But the one with the underscore is
not. So say if we delete that and we put
a one on the end and save it. Go back to
our docs. Now we have two. That's a good
way to hide these from your
documentation. So if you don't want you
want them private, you don't want anyone
to see it. We save the change and back
and save it. Come back to our docs. Now
it's gone again. Well, we're going to
keep it public with no underscore. I'm
delete this one
and save the script. Now, underneath
here, I'm going to add a variable
energy and it's going to be of type int.
Set it to 10
and delete that and save there. I'm
update this function. I'm going to get
rid of this print statement here. What
I'm going to do, I'm going to write in
energy just be plus= 5. And then when we
call this function, we're going to
actually emit this signal that we write
up here. Energy changed. We do that by
saying energy energy changed. And then
we need to emit and we need to emit a
callable
of type variable. The variable we're
going to use is this is going to be the
energy right here.
Now we just type in energy.
So whatever we change this energy to be
we're going to emit that energy and it's
become the new energy amount
right here. Make this bigger. So
basically what this is doing is emitting
the signal with the data.
Now we still need to update the UI. So
we have a helper function looking all
right should be function of just update
label very straightforward the amount we
want to update the labels with the int
and it's going to return void
avoid and then what we want to do here
is access with the money symbol we're
going to access the label node right
here and we're going to access the text
in that label node change it to energy
colon space enter concatenate plus
change the amount into a string. You
have to do that to put it in the label
or else it won't work. Make sure we
string the amount.
So the label will display the proper
amount of energy we currently have. And
for list to work well, we need to
actually connect to this just like we
did to the button up here. Back in our
ready script underneath our button
connection, we're going to have another
connection to our actual energy changed
custom signal we just wrote. So energy
changed
and then we just need to connect to it.
We're going to pass in the recipe,
not the whole cake, just the recipe to
give GDAU to say what happens when this
gets emitted. What we want to happen is
we want to update the label.
Let's save that. But when the game
starts, well, we want to actually update
the label right away. So, we want to
give GDAU the whole cake. So, we want to
make sure it uses not just the recipe,
but it makes it right away. So, we need
to actually call this update label right
away. We need to pass in an amount here.
We're going to pass in well the energy
that we set. some energy.
So this here is making the whole cake.
This here is giving GDO the recipe to
make the cake when we call it. I'm going
to save the scene. Save the script. It's
going to run it. This button up here
current scene.
All right.
Our energy set to 10. Now we're going to
click the recharge up by five. You see
our script back here. Energy plus equals
5. We're emitting that and adding it to
our energy in our label.
So, every time you click it, we get five
more.
Now, you've reached a checkpoint. I want
you to add a timer node to the root node
of the scene. Turn the auto start to on.
And then in the script, write a function
just like we have with the on recharge
clicked. But where you're going to label
it is you're going to call it function
on timer tick. That's going to return
the void.
Then inside the function, what we're
gonna do, I want you to minus the energy
by one
and then I want you to emit the energy
changed
signal. It's very familiar to the auto
recharge clicked. Just have to adapt it
to the energy
by one. Minusing the energy by one. And
then just like in the button here,
connect to the timer
and then connect to the signal name of
timeout.
We'll connect that to that new function
that we just wrote.
Go and pause it now. Give it a try.
We all figure that out. If not, that's
fine. We'll go and follow along with me.
So, I'm back in our game node here.
We're going to right click, add child
node timer.
In the timer itself, we're going to go
to the inspector, turn auto start to on,
and then in the script,
I'm going to write a new function on
timer tick. And to minus the energy by
one, all I got to do is say energy minus
equals 1. Then emit the energy changed.
We're going to do energy changed.
Then we need to emit the energy
just like that. So literally quite
literally just the way we did it here.
Now we need to connect the timer just
like we did the button. Money sim timer
timeout
connect.
And we need to connect to the on timer
tick that we just wrote.
right there with no parenthesis.
Go and save that. Then we go and give it
a try. Run current scene.
You see our energy ticking down by one
every second and recharge still works as
well. Now, a quick tip before the big
finale. Sometimes you just want to wait
for a signal once. We can use the
keyword await for that.
So, in our ready function at the end
here, well, we're just going to write
print and then we're write waiting
for the player to start.
Okay. And then we just need to stop the
timer. So, money symbol timer. Then
we're going to stop.
So, if it's auto started, we're going to
stop it initially and we use the keyword
await. And we're gonna wait for button
keyword to money symbol button
pressed.
So this way we're just going to wait for
this press signal to be initialized. So
when the button is pressed
finally.
So this basically pseudo pauses the
game. Well after the button is pressed
well we're going to print out game
started.
That's a fun way to use signals for for
anything you really want to wait for a
button or a time or a countdown or
otherwise. So after the game is started,
well, we'll take the title and then
we're just going to start it. Then the
countdown will begin
on our energy levels.
So save that. We're going to run the
scene
and notice here waiting for player to
start. Energy level is not decreasing.
It's waiting for us to press this button
right here. Await button pressed. So
when we push this button, then our timer
will start and then it'll start
decreasing our energy.
14 13 gain started. Now we can play as
we did before. Perfect.
Now from the final boss, the event bus
or signal bus. Right now, if our energy
hits zero, we want the game to stop. And
a game over UI to appear, maybe a sound
to play if you want. Then connecting all
these nodes together can get messy. So
that's what the signal bus is for. It's
like a global radio station, which you
can listen to, which all our scripts
listen to for signal. Back our project
here. Make this smaller. Just our root
folder here. Create name script. And I'm
just going to call it signal bus.
Signal_bus.
I'm going double click in there. Let me
get rid of this boiler plate code. The
only thing I want in here is signal. And
we're going to use the on game over.
That's all we need for now. You can put
as many as you like in here. We'll go
and save this. Well, we need to make it
global. How do we do that? We go with
our project project settings.
and go into our globals. We're going to
set a path with this little folder icon.
We're going to click on our signal bus
script we just wrote. Open.
We want this node name to be signal bus
just like it is. Should autocomplete
just like that. Then we're going to add
now we have it enabled as a global
variable. That's all we need for now. We
close that. Now back to our game script.
going to update our on timer tick
function. Scroll down now and below the
energy change emit. What we can do here
is we're going to ask
the signal bus and this time for time
over
game over. So if the energy is less than
or equal to zero, we want to do is call
our signal bus and we want to all the
signal we wrote the signal bus on game
over.
So we're should be right here on game
over and we want to emit that.
And when we emit game over, well, we do
want to stop the timer as well. So money
symbols timer stop.
Let's save that. Enter down a couple
times. And we need another function here
to handle the game over. So function
handle game over. Let's give a return
void. And in this function, well, we're
going to use our label,
the money symbol label, and we're change
the text of the label. Instead of
displaying the energy, it's going to
display game over.
Then we want to disable our button so we
can't keep giving ourselves edge. So the
button
disabled
equals true.
Then we're going to print in the output
that the event bus
told me to shut down. Perfect. And
remember none of this will work if we
don't actually connect to it. So open
our ready function up here.
and our signal connections. Well, we
need to also connect to our signal bus
on game over
and connect. And what do we want to what
recipe do we want to give to this
connection? Well, the on game over the
handle game over
function we just wrote is going to be
called with this on game over emitted
signal. Great. going to save that.
And then let's run this scene.
Now
we're not running until we click the
button with our awaiting signal. Waiting
play to start. Recharge. All right. Our
timer is counting down. I'm going to let
it count to zero.
All right. Game over. Recharge button is
disabled.
The event bus told me to shut down
that we covered a lot. Built-in signals,
code connection signals, private signals
in GTO 4.6F
and passing data with custom signals,
the await keyword for signals and
finally the event bus pattern or signal
bus pattern for signals. Now this is the
foundation of clean architecture in
GDAU. The summary is use editor
connections like you did in the
beginning for static things that never
change like your main menu buttons,
options, buttons, and then use the code
connections for everything else,
especially game mechanics, and spawned
objects. Now, if you found this helpful
at all or fun, leave a comment what your
GDO gamedev goals are. Please like,
subscribe, and hit that notification
bell. It really helps out the channel.
And thank you to our current and past
Patreon and coffee members. Your
generous support keeps the channel
moving. If you want early access to
tutorials, source code, or suggesting
future tutorials, please consider
becoming a member yourself. The links
are in the description. I'm Spaghetti
Syntax, and remember, always stay
curious, and I'll see you at the next
checkpoint.
Ask follow-up questions or revisit key timestamps.
This video tutorial covers the concept of signals in GDevelop, starting with basic button signals and progressing to more advanced features like custom signals, the `await` keyword, and implementing an event bus. It demonstrates how to connect signals using both the editor and code, explains the difference between editor and code connections, and highlights new features in GDevelop 4.6, such as private signals. The tutorial concludes by showing how to use an event bus for global communication between different parts of a game, facilitating cleaner architecture.
Videos recently processed by our community