In this lesson, we will add a score field to our form and scoreboard.
We will first update the scoreboard to accept a name and a score in each row.
We will create a new scene representing one score line to achieve that.
We will then add a score field to the form and send both the player name and the score to the scoreboard when pressing the OkButton.
We will first design a scene to represent a row.
It should be a row with a
for the score and another for the player’s name.Create a new scene and click the Other Node button to create an
.Rename the node to ScoreLine and add two
nodes as its children.Rename the
nodes to PointsLabel and NameLabel respectively to distinguish them.We can tint the score in yellow to distinguish it from the player’s name.
First, we want to add some placeholder text to each label. To do so, select each node and in the Inspector, write something in its Text field.
Then, select the PointsLabel. In the Inspector, scroll down to the Visibility category below the
node section.Expand the category and change the Modulate color to yellow.
Save the scene in the Scoreboard/
directory and attach a
script to the ScoreLine node by right-clicking on it and
selecting Attach Script.
We define two functions that we’ll use as an interface for the Scoreboard to display points and a name.
extends HBoxContainer
# We first get the two label nodes and store them with onready variables.
onready var points_label := $PointsLabel
onready var name_label := $NameLabel
# For each of the labels, we define a function that we will call from the
# scoreboard.
func set_player_points(points_value: String) -> void:
# The function String.pad_zeros() adds zeros in front of the score to make
# every score the same size. In this case, 6 digits.
= points_value.pad_zeros(6)
points_label.text
func set_player_name(player_name: String) -> void:
= player_name name_label.text
Both functions are similar: they update the labels’ text.
Defining and using functions provides a safe way to use your scenes
compared to directly accessing nodes like points_label
.
It allows you later add instructions inside the functions without causing errors in the game.
Open the Scoreboard script and replace the
add_line()
function with the following code. We will break
it down in a moment.
# Note the addition of a new parameter: player points.
func add_line(player_name: String, player_points: String) -> void:
# Loads the ScoreLine scene and creates a new instance of it.
var line := preload("ScoreLine.tscn").instance()
# We can add the ScoreLine instance as a child of the ScoresColumn like
# plain nodes.
add_child(line)
scores_column.# As we instanced the ScoreLine scene, we can call the functions we defined
# on it.
set_player_name(player_name)
line.set_player_points(player_points) line.
In the first line, we do two things:
line
variable.The preload()
function allows you to load a resource
file, like a scene, using an absolute or a relative path.
It’s a special function that tells Godot to load the scene once upon launching the game and later keep it in memory. That way, we can quickly create new instances of it.
Like before, we add the line as a child of the ScoresColumn. In that, a scene instance acts a bit like a node: you can add it as a child of another node.
The last two lines call the two functions we defined in the ScoreLine scene and pass the player name and score, respectively.
Now, we will add a points field to our ScoreForm.
Open the ScoreForm scene and duplicate the NameField node. Rename the new node to PointsField.
In the Inspector, we can remove the Placeholder -> Text.
In the script, we need to get our point field in a new
onready
variable. Around the top, add the variable.
onready var points_field := $HBoxContainer/PointsField
Then, we need to update our signal callback function.
func _on_OkButton_pressed() -> void:
# ...
add_line(name_field.text, points_field.text)
scoreboard.# ...
We update the call to the Scoreboard.add_line()
function
and pass it the PointField’s text.
Currently, the player can add a new name and score to the scoreboard even if the fields are empty.
We can use a condition at the start of the function to prevent that.
func _on_OkButton_pressed() -> void:
# If either field contains no text, we stop the function.
if not name_field.text or not points_field.text:
return
# ...
Notice that we don’t write anything after the return
keyword in the code listing above. Writing only return
ends
the function’s execution and does not return any value.
This code change completes the lesson. You can now run the scene, enter a name and a score, and it should appear on the scoreboard.
Technically, you can type any text in the score field.
We don’t bother to ensure that you type a number here as, in a complete game, the score would be calculated for the player.
Open the practice The inventory grid.
Once you complete the practice, the running scene should look like this.
Open the practice The poem.
The running scene should look like this.
Open the practice The to-do list.
The final result should look like this.
Here is the complete code for the scenes so far.
ScoreLine.gd
extends HBoxContainer
# We first get the two label nodes and store them with onready variables.
onready var points_label := $PointsLabel
onready var name_label := $NameLabel
# For each of the labels, we define a function that we will call from the
# scoreboard.
func set_player_points(points_value: String) -> void:
# The function String.pad_zeros() adds zeros in front of the score to make
# every score the same size. In this case, 6 digits.
= points_value.pad_zeros(6)
points_label.text
func set_player_name(player_name: String) -> void:
= player_name name_label.text
Scoreboard.gd
extends PanelContainer
onready var scores_column := $MarginContainer/VBoxContainer/ScoresColumn
# Note the addition of a new parameter: player points.
func add_line(player_name: String, player_points: String) -> void:
# Loads the ScoreLine scene and creates a new instance of it.
var line := preload("ScoreLine.tscn").instance()
# We can add the ScoreLine instance as a child of the ScoresColumn like
# plain nodes.
add_child(line)
scores_column.# As we instanced the ScoreLine scene, we can call the functions we defined
# on it.
set_player_name(player_name)
line.set_player_points(player_points)
line.
func _on_HideButton_pressed() -> void:
hide()
ScoreForm.gd
extends Control
onready var scoreboard := $Scoreboard
onready var name_field := $HBoxContainer/NameField
onready var points_field := $HBoxContainer/PointsField
func _on_OkButton_pressed() -> void:
# If either field contains no text, we stop the function.
if not name_field.text or not points_field.text:
return
show()
scoreboard.add_line(name_field.text, points_field.text)
scoreboard.= "" name_field.text