I am currently trying to build my first ever game. I had some great progress in the first few weeks, but now I want to improve some things that are annoying me. My major pain point right now is the dialog system.
In my project I have NPCs that the player can interact with if they come close. To achieve this I use the body_entered and body_exited signals in the NPC's script like this:
func _on_worker_talking_area_body_entered(body):
if body.name == "Player":
$BubbleAnimation.show()
$BubbleAnimation.play("on")
$DialogLayer/Dialog/Panel/DialogText.text = approach_text
$DialogLayer.show()
func _on_worker_talking_area_body_exited(body):
if body.name == "Player":
$BubbleAnimation.stop()
$BubbleAnimation.hide()
$DialogLayer.hide()`
This works nicely, so that when the player comes near an NPC a little bubble appears. Now the player can interact using different buttons ("space", "y" and "n") to trigger a dialog depending on the state of the NPC. I get these inputs like this:
func _input(event: InputEvent):
if event.is_action_pressed("interaction") and $BubbleAnimation.visible:
if worker_name == "welcome_worker" and state == 0:
await $DialogLayer.split_text(get_current_text())
state = 1
state_changed.emit()
if (worker_name == "crane_worker" or worker_name == "milling_machine_worker") \
and state == 1:
await $DialogLayer.split_text(get_current_text())
state = 2
if (worker_name == "crane_worker" or worker_name == "milling_machine_worker") \
and state == 2:
await $DialogLayer.split_text(get_current_text())
if event.is_action_pressed("no") and state == 2 and $BubbleAnimation.visible:
state = 3
await $DialogLayer.split_text(get_current_text())
state_changed.emit()
if event.is_action_pressed("yes") and state == 2 and $BubbleAnimation.visible:
state = 4
await $DialogLayer.split_text(get_current_text())
state_changed.emit()`
The text is then displayed in the DialogLayer
which displays it by scrolling letter by letter:
func split_text(input_text: String) -> void:
$Dialog.show()
var text_array = input_text.split("/")
for text_piece in text_array:
scroll_text(text_piece)
await get_tree().create_timer(5.5).timeout
$Dialog.hide()
func scroll_text(input_text: String) -> void:
var text = input_text
var visible_characters = 0
for i in text.length():
visible_characters += 1
await get_tree().create_timer(0.1).timeout
$Dialog/Panel/DialogText.text = text.left(visible_characters)`
Now there are several things that don't work properly here:
So I was wondering how could I set up such a dialog system properly? What are some guidelines or tips how to get this working? I would really apreciate every input, as I am quite stuck right now.
The player can leave the "talking area" while the text is scrolling, which will stop displaying the text, but the scrolling continues without the player seeing it.
Maybe have the player have an input_lock
bool that stops it from moving during dialog or a cutscene? If you're using a pattern like FSM you might be able to work a 'frozen' state into it that can be switched to during dialog.
It is super annoying to wait for 5.5 seconds for each line of dialog, if that line of dialog is super short. So it would be nice to give the player the ability to skip to the end using space ("interaction").
Maybe try something like this:
async func scroll_text(input_text: String) -> void:
for i in input_text.length():
# smth here
By making the scroll text func async, you can await scroll_text(text_piece)
and that will wait however long the scroll text function takes