In this lesson, we’ll add code to the scoreboard to display a list of names.
Right-click on the Scoreboard node and select Attach Script to give it a new script.
Ensure that the template is set to Empty, then click Create.
We want to list names and scores in the ScoresColumn node. For each name, we’ll use a
node.As we’ll need various names, we don’t want to create label nodes by hand.
Instead, we’ll use code to create labels dynamically.
So far, we have created nodes in the editor using the Create New Node window.
You can also create nodes using GDScript code, like so:
.new()
. For example, Timer.new()
, or
Sprite.new()
.Sprite.texture
.add_child()
member function.Until you add a node as a child of another, it only exists in the computer’s memory and does not affect the display.
Here’s a code example to create
nodes using code.func add_label(text: String) -> void:
var label := Label.new()
= text
label.text # This call adds the label as a child of the node with this script attached.
add_child(label)
And another one creating a
.func add_timer(duration: float) -> void:
# We create a new Timer node.
var timer := Timer.new()
# We set the timer to last duration seconds and not cycle.
= duration
timer.wait_time = true
timer.one_shot # And we add it as a child of the node with the script attached.
add_child(timer)
The advantage of using code is that we can create as many nodes as we need without knowing their count in advance.
Let’s code a function to add a name to the scoreboard. We’ll call it
add_line()
as we’ll later use it to register the player’s
name and score.
We first create a line
variable. We then access the label’s text
member variable through the line
variable.
func add_line(player_name: String) -> void:
var line := Label.new()
= player_name line.text
Setting a node doesn’t make it appear on the screen. To display the label, we must add it to our node tree.
We want to add labels as children of the ScoresColumn node so they arrange vertically.
So we first get the ScoresColumn node, and add the add_child()
function.
func add_line(player_name: String) -> void:
#...
$MarginContainer/VBoxContainer/ScoresColumn.add_child(line)
Note: In Godot, the $
is an alias for
the get_node()
function.
You give it the path to a node, and the function returns a reference to the node. Getting the node allows you to access the node’s functions and variables.
You can see how the node path for the ScoresColumn is long and difficult to read. Our code would be more readable with a variable to label it.
# We want to add the line in our ScoresColumn, so we call add_child() on the
# ScoresColumn node.
add_child(line) scores_column.
A good practice in GDScript is to create member variables for nodes you use at the top of your script.
It shows you the nodes that the script needs to work at a glance.
However, we can’t just store a node in a member variable. We need to wait for a node to be in its ready state before we access it.
When you run a scene, Godot creates nodes and adds them to the scene
tree sequentially. Until then, child nodes are not accessible in your
code: you can’t use the $
sign to access the node.
We say that the nodes are not ready.
Godot provides a special function you can write to run code when all child nodes are ready:
func _ready() -> void:
pass
You can use it to get a child node and store it in a script member variable.
var scores_column: Node
func _ready() -> void:
= $MarginContainer/VBoxContainer/ScoresColumn scores_column
Then, every time you want to access the ScoresColumn node,
you can write scores_column
.
As assigning references to variables is very common, GDScript
provides a keyword to set variables when children are ready:
onready
.
We can use it to store the ScoresColumn in a variable.
You’ll want to add the following line above the add_line()
function.
onready var scores_column := $MarginContainer/VBoxContainer/ScoresColumn
Note that the onready
must come before the
var
keyword. Also, it only works when defining a member
variable.
With the line above, you can use the variable in the
add_line()
function. Your code should look like this:
extends PanelContainer
onready var scores_column := $MarginContainer/VBoxContainer/ScoresColumn
func add_line(player_name: String) -> void:
var line := Label.new()
= player_name
line.text # We want to add the line in our ScoresColumn, so we call add_child() on the
# ScoresColumn node.
add_child(line) scores_column.
To add a line to the scoreboard, you need to call the
add_line()
function.
We must do this inside the _ready()
function as the
add_line()
function requires the ScoresColumn
node.
func _ready() -> void:
add_line("Athos")
add_line("Portos")
add_line("Aramis")
You can call the function as many times as you’d like. If you run the scene (F6), you should see a list of names.
The _ready()
function, like the _process()
function, is defined in the Godot engine. It exists on every node.
When you run a scene, Godot reads your scene file and prepares to create a tree of nodes.
Godot first creates the nodes sequentially, from top to bottom.
Then, Godot calls the _ready()
function on the nodes
following two rules:
_ready()
on the children before the parent.In our Scoreboard scene, the engine will create the nodes from top to bottom, making them ready to use, starting with the
, then the , and then the ScoresColumn, in this order.Then, it will make the parent
ready, then the , and finally, the Scoreboard.This approach allows you to have child nodes initialize themselves
properly before getting them in the _ready()
function or
using the onready
keyword.
The void
keyword after the add_line()
and
_ready()
function definitions means that the functions do
not return a value.
If you specify that the function is void
, Godot will
warn you if you or a teammate tries to return a value from it.
Here is the complete code for this first lesson.
extends PanelContainer
onready var scores_column := $MarginContainer/VBoxContainer/ScoresColumn
func _ready() -> void:
add_line("Athos")
add_line("Portos")
add_line("Aramis")
func add_line(player_name: String) -> void:
var line := Label.new()
= player_name
line.text # We want to add the line in our ScoresColumn, so we call add_child() on the
# ScoresColumn node.
add_child(line) scores_column.