Godot Version
v4.1.2.stable.official [399c9dc39]
Question
This is a 2 pronged question, but I’m currently programming a typewriter style dialogue system for an RPG project I’m working on, and I want to have it so the dialogue box reads off the text.
I noticed a particular quirk in the code i’ve written. The dialogue itself seems to play on for longer than it should, from what I can only assume is because the text includes bbcode markdown tags when it checks the length of the string, but I’m not sure how to go about detecting this and working around this issue.
At the same time, I want to also detect when the next character in said string is a space so it can skip over playing a sound for it.
Below I’ve included the current code I have for the dialogue system. I’m still just learning GDScript, so a lot of the code is a bit messy and unoptimized. I would greatly appreciate any help with this though!
extends Control
@export var dialogPath = "res://assets/data/dialogue/test/test.json"
@export var textboxPath = "res://assets/images/dialogue/"
@export var portraitPath = "res://assets/images/dialogue/portraits/"
@export var textSoundPath = "res://assets/sounds/text/"
@export var textSpeed : float = 0.04
var dialog
var sound
var phraseNum = 0
var finished = false
func _ready():
dialog = getDialog()
assert(dialog, "Dialog not found")
create_tween().tween_property($DarkenBG, "modulate", Color(0, 0, 0, 0.25), 1).set_trans(Tween.TRANS_EXPO).set_ease(Tween.EASE_OUT)
create_tween().tween_property($DialogueBox, "position:y", $DialogueBox.position.y - 100, 0.8).set_trans(Tween.TRANS_BACK).set_ease(Tween.EASE_OUT)
create_tween().tween_property($TopBar, "position:y", $TopBar.position.y + 50, 1).set_trans(Tween.TRANS_EXPO).set_ease(Tween.EASE_OUT)
create_tween().tween_property($BottomBar, "position:y", $BottomBar.position.y - 50, 1).set_trans(Tween.TRANS_EXPO).set_ease(Tween.EASE_OUT)
create_tween().tween_property($Portrait_Left, "position:x", $Portrait_Left.position.x + 300, 1).set_trans(Tween.TRANS_BACK).set_ease(Tween.EASE_OUT)
create_tween().tween_property($Portrait_Right, "position:x", $Portrait_Right.position.x - 300, 1).set_trans(Tween.TRANS_BACK).set_ease(Tween.EASE_OUT)
$Timer.wait_time = 1.2
nextPhrase()
func _process(_delta):
#$Indicator.visible = finished
if Input.is_action_just_pressed("game_interact"):
if finished:
nextPhrase()
else:
$Text.visible_characters = len($Text.text)
func getDialog() -> Array:
var output = JSON.parse_string(FileAccess.get_file_as_string(dialogPath))
if typeof(output) == TYPE_ARRAY:
return output
else:
return []
func nextPhrase() -> void:
if phraseNum >= len(dialog):
$Timer.wait_time = 0.8
create_tween().tween_property($DarkenBG, "modulate", Color(0, 0, 0, 0), 1).set_trans(Tween.TRANS_EXPO).set_ease(Tween.EASE_OUT)
create_tween().tween_property($DialogueBox, "position:y", $DialogueBox.position.y + 100, 0.6).set_trans(Tween.TRANS_BACK).set_ease(Tween.EASE_OUT)
create_tween().tween_property($Text, "position:y", $Text.position.y + 100, 0.6).set_trans(Tween.TRANS_BACK).set_ease(Tween.EASE_OUT)
create_tween().tween_property($Name, "position:y", $Text.position.y + 100, 0.6).set_trans(Tween.TRANS_BACK).set_ease(Tween.EASE_OUT)
create_tween().tween_property($TopBar, "position:y", $TopBar.position.y - 50, 0.8).set_trans(Tween.TRANS_EXPO).set_ease(Tween.EASE_OUT)
create_tween().tween_property($BottomBar, "position:y", $BottomBar.position.y + 50, 0.8).set_trans(Tween.TRANS_EXPO).set_ease(Tween.EASE_OUT)
create_tween().tween_property($Portrait_Left, "position:x", $Portrait_Left.position.x - 300, 0.8).set_trans(Tween.TRANS_BACK).set_ease(Tween.EASE_OUT)
create_tween().tween_property($Portrait_Right, "position:x", $Portrait_Right.position.x + 300, 0.8).set_trans(Tween.TRANS_BACK).set_ease(Tween.EASE_OUT)
$Timer.start()
await $Timer.timeout
queue_free()
return
finished = false
#Dialogue API - Mode & Name
var dialogMode = dialog[phraseNum]["Mode"]
$DialogueBox/AnimationPlayer.play(dialogMode)
#Dialogue API - Text, Textboxes and Sound
$Text.bbcode_text = dialog[phraseNum]["Text"]
$Text.set_position(Vector2(-152,-50))
if dialogMode != "M":
var box = textboxPath + "textbox_" + dialog[phraseNum]["Name_" + dialogMode] + ".png"
if FileAccess.file_exists(box):
$DialogueBox.texture = load(box)
else: $DialogueBox.texture = load(textboxPath + "textbox_generic.png")
sound = textSoundPath + "text_" + dialog[phraseNum]["Name_" + dialogMode] + ".ogg"
if FileAccess.file_exists(sound):
$AudioStreamPlayer.stream = load(sound)
else: $AudioStreamPlayer.stream = load(textSoundPath + "text_generic.ogg")
if dialogMode == "L":
$Text.set_position(Vector2(-72,-50))
$Name.set_position(Vector2(166, -82))
create_tween().tween_property($Portrait_Left, "modulate", Color(1, 1, 1, 1), 1).set_trans(Tween.TRANS_EXPO).set_ease(Tween.EASE_OUT)
create_tween().tween_property($Portrait_Right, "modulate", Color(0.5, 0.5, 0.5, 1), 1).set_trans(Tween.TRANS_EXPO).set_ease(Tween.EASE_OUT)
elif dialogMode == "R":
$Text.set_position(Vector2(-232,-50))
$Name.set_position(Vector2(-226, -82))
create_tween().tween_property($Portrait_Left, "modulate", Color(0.5, 0.5, 0.5, 1), 1).set_trans(Tween.TRANS_EXPO).set_ease(Tween.EASE_OUT)
create_tween().tween_property($Portrait_Right, "modulate", Color(1, 1, 1, 1), 1).set_trans(Tween.TRANS_EXPO).set_ease(Tween.EASE_OUT)
elif dialogMode == "M":
create_tween().tween_property($Portrait_Left, "modulate", Color(0.5, 0.5, 0.5, 1), 1).set_trans(Tween.TRANS_EXPO).set_ease(Tween.EASE_OUT)
create_tween().tween_property($Portrait_Right, "modulate", Color(0.5, 0.5, 0.5, 1), 1).set_trans(Tween.TRANS_EXPO).set_ease(Tween.EASE_OUT)
$Text.visible_characters = 0
#Dialogue API - Portraits
var img_l = portraitPath + dialog[phraseNum]["Name_L"] + "_" + dialog[phraseNum]["Emote_L"] + "_L.png"
if FileAccess.file_exists(img_l):
$Portrait_Left.texture = load(img_l)
else: $Portrait_Left.texture = null
var img_r = portraitPath + dialog[phraseNum]["Name_R"] + "_" + dialog[phraseNum]["Emote_R"] + "_R.png"
if FileAccess.file_exists(img_r):
$Portrait_Right.texture = load(img_r)
else: $Portrait_Right.texture = null
#Dialogue API - Initial Timer
$Timer.start()
await $Timer.timeout
$Timer.wait_time = textSpeed
if dialogMode == "L" or dialogMode == "R":
$Name.bbcode_text = dialog[phraseNum]["Name_" + dialogMode]
else: $Name.bbcode_text = " "
#Dialogue API - Text Displaying
while $Text.visible_characters < len($Text.text):
$Text.visible_characters += 1
$AudioStreamPlayer.play(1)
$Timer.start()
await $Timer.timeout
finished = true
phraseNum += 1
return