In this lesson, we’ll write the code to display a line of dialogue with the correct character portrait.
The code is similar to the slideshow series, so we’ll go through some code samples faster than before.
Like before, we’ll create a function to show a line of dialogue that takes the unique ID and displays the corresponding line.
We want to do three things:
dialogue
dictionary.We’ll split this process into three functions. Let’s start with two functions that update the
’s text and the displayed expression.First is the set_text()
function. It changes the ’s bbcode_text
property.
has both a text
and a
bbcode_text
property. You need to use
bbcode_text
for BBCode text formatting to work.
onready var rich_text_label := $MarginContainer/VBoxContainer/HBoxContainer/RichTextLabel
func set_text(new_text: String) -> void:
= new_text rich_text_label.bbcode_text
Like in the slideshow, we create a function because we’ll later animate the text, which will require more lines of code.
Our dialogue
variable stores the desired character’s
facial expression as a instead of preloading textures.
# ...
"expression": "neutral",
# ...
In general, you do not want to hardcode preloaded textures in your dialogue data because it becomes difficult to change once you have thousands of dialogue lines.
If you decide to move the portrait files, you will have to change
every call to the preload()
function to use the new
paths.
When coding games, we very often need to move files like this.
To make it easier to update loaded file paths, we can write a function that centralizes all loading in one place.
The function takes a
parameter and displays the corresponding texture to use.We can use conditions like the following to use a given texture depending on the expression.
onready var texture_rect := $MarginContainer/VBoxContainer/HBoxContainer/TextureRect
func set_expression(expression: String) -> void:
if expression == "sad":
= preload("portraits/sophia_sad.png")
texture_rect.texture # Elif is the contraction of "else if." This block will run if the previous
# condition didn't pass.
elif expression == "happy":
= preload("portraits/sophia_happy.png")
texture_rect.texture # Any `expression` that we don't list above will display the neutral
# character portrait.
else:
= preload("portraits/sophia_neutral.png") texture_rect.texture
We now have the two functions we need to update the displayed dialogue line.
We define a new show_line()
function that extracts the
line’s data from the dialogue
variable and sets the text
and the character’s texture. We’ll call this function to advance through
the dialogue.
Note the explanations inside of code comments. We’ll place explanations inside the code frequently moving forward to keep them as close as possible.
func show_line(id: int) -> void:
# We extract the line's data from the `dialogue` variable.
var line_data: Dictionary = dialogue[id]
# We then pass the text and expression values of the line's data to
# functions that update the displayed text and character portrait.
set_text(line_data.text)
set_expression(line_data.expression)
Finally, in the _ready()
function, we call the
show_line()
function.
func _ready() -> void:
show_line(0)
And that’s all we need to display some text and update the character’s portrait.
If you run the scene with F6, you should see the first line of dialogue.
There is a little problem, though. The text contains BBCode so the words “wake up” should appear in italics.
var dialogue = {
0: {
"text": "Hey, [i]wake up![/i] It's time to make video games.",
# ...
Italics don’t work because we didn’t provide our
node with the necessary font files.A
needs dedicated font resources to display text in italics, bold, and bold-italics.Let’s add font overrides to the node to see our formatted text. We
prepared several DialogueBoxes/common/fonts/
folder.
Select the
node in the scene dock and, in the Inspector, expand the Theme Overrides -> Fonts category.In the FileSystem dock, open the
DialogueBoxes/common/fonts/
directory. You want to drag and
drop fonts onto the correct slots:
font_text_bold.tres
goes in the Bold Font
slot.font_text_italics.tres
goes in the Italics
Font slot.font_text_bold_italics.tres
goes in the Bold
Italics Font slot.After assigning the fonts, your Inspector should look like this.
You do not need to override the Normal Font as the
will use the default font from our resource.Lastly, the Mono Font allows you to format code, which we don’t have in our text data. We can ignore it.
Before seeing the formatted text, you need to turn on Bbcode -> Enabled on the
node.You should now see text in italics and bold when running the scene.
You could have all the code we wrote above in a single
show_line()
function, which would work the same.
Why do we split it, then?
There are two reasons to split your code into functions:
In this course, we mainly use functions for readability and learning. We try to group related instructions into chunks that aren’t too overwhelming for you to process.
You might wonder how to know when to split code into functions. Some professionals advocate using many short functions, while others tend to use much longer ones.
Either style can work fine, but it takes experience with both to get their advantages and drawbacks. For now, please don’t worry about it too much and focus on making your code work.
In the next lesson, we’ll write code to generate buttons from our dialogue’s data.