Trying to do my own dialogue system

Godot Version

3.5.3

Question

I’m trying to do a dialogue system by my own because i don’t understand how to use the dialogue systems addons of the community, they are kind of hard to implement in a project (at least for me :sweat_smile:).

My idea of how to make that dialogue system is by a CSV file that has the character name and the dialog text (I’ll make a CSV per scene, environment, action, whatever) and by that get all the information that i need for the dialogue.

So, I’m having a problem on these lines:

if !_dialogue_file == null:
		if _i < dialog_data.size():
			character = dialog_data[_i]["Character"]
			dialogue = dialog_data[_i]["Dialogue"]
			var _dialogue = dialogue.replace("'","")
			character_name_text.text = character
			dialogue_label.bbcode_text = _dialogue
			
			finished_dialogue = false
			
			if Input.is_action_just_pressed("Interact"):
				
				if finished_typing:
					_i += 1
					if !interact_key_was_pressed:
						dialogue_label.percent_visible = 0
						start_typing_delay.start()
		elif _i == dialog_data.size():
			finished_dialogue = true

my idea is to say that finished_dialog is true when _i has the same value as the one returned by dialog_data.size() (5 in my case) but as in programming zero is a valid number then it triggers the problem that the dialog is supposed to be finished but according to elif it is not like that (that is to say that when _i is four the dialog should be finished), since the CSV file has four lines (discarding the one that says “Character, Dialogue” ) and my idea is that when _i is four finished_dialog is true.

Btw, here is the whole code of the dialogue system in case if you want to review it

extends Control

onready var dialogue_label = $"Dialogue box/Text2"
onready var character_name_text = $Character_name_text
onready var animation_player = $AnimationPlayer

onready var interact_key = $"VBoxContainer/Interact key"
onready var _i_text = $VBoxContainer/_i
onready var finished_typing_text = $VBoxContainer/finished_typing
onready var start_typing_text = $VBoxContainer/start_typing
onready var is_typing_text = $VBoxContainer/is_typing
onready var no_moer_lines_text = $VBoxContainer/no_more_lines
onready var cant_call_exit_animation_label = $VBoxContainer/cant_call_exit_animation

var character_count : float
var interact_key_was_pressed := false
var is_typing := false
var cant_call_enter_animation := false
var cant_call_exit_animation := false
var animation_finished := false
var finished_typing : bool = false
var start_typing : bool = false
var file_already_readed := false
var finished_dialogue : bool = true
var start_typing_delay := Timer.new()
var finished_typing_delay := Timer.new()
var _delta : float
var _i : int = 0

var _text : String
var _dialogue_file

var character : String
var dialogue : String

var dialog_data : Array

func _ready() -> void:
	Engine.target_fps = 60
	
	start_typing_delay.one_shot = true
	start_typing_delay.wait_time = 0.25
	start_typing_delay.connect("timeout",self,"_on_start_typing_delay_timeout")
	add_child(start_typing_delay)

	finished_typing_delay.one_shot = true
	finished_typing_delay.wait_time = 0.25
	finished_typing_delay.connect("timeout",self,"_on_finished_typing_delay_timeout")
	add_child(finished_typing_delay)
	
	dialogue_label.percent_visible = 0
	character_count = dialogue_label.bbcode_text.length()
	
func _process(delta: float) -> void:
	_delta = delta
	
	if start_typing:
		type_dialogue()
	
	if !_dialogue_file == null:
		if _i < dialog_data.size():
			character = dialog_data[_i]["Character"]
			dialogue = dialog_data[_i]["Dialogue"]
			var _dialogue = dialogue.replace("'","")
			character_name_text.text = character
			dialogue_label.bbcode_text = _dialogue
			
			finished_dialogue = false
			
			if Input.is_action_just_pressed("Interact"):
				
				if finished_typing:
					_i += 1
					if !interact_key_was_pressed:
						dialogue_label.percent_visible = 0
						start_typing_delay.start()
		elif _i == dialog_data.size():
			finished_dialogue = true

	if Input.is_action_just_pressed("Interact"):
		interact_key_was_pressed = true
		
		if file_already_readed == false:
			read_dialogue_file("res://Nuevo Hoja de cálculo OpenDocument.csv")
	
		if is_typing:
			dialogue_label.percent_visible = 1
		if finished_dialogue:
			dialogue_label.text = ""
			
		if finished_typing == true and finished_dialogue:
			if !cant_call_exit_animation:
				animation_player.play("dialogue_exit")
				print("a")
	else:
		interact_key_was_pressed = false
		
	interact_key.text = "interact key: " + str(interact_key_was_pressed)
	_i_text.text = "_i: " + str(_i)
	start_typing_text.text = "start_typing: " + str(start_typing)
	finished_typing_text.text = "finished_typing: " + str(finished_typing)
	is_typing_text.text = "is_typing: " + str(is_typing)
	no_moer_lines_text.text = "no more lines: " + str(finished_dialogue)
	cant_call_exit_animation_label.text = "cant_call_exit_animation_label: " + str(cant_call_exit_animation)
		
func read_dialogue_file(dialogue_file: String):
	var file = File.new()
	_dialogue_file = dialogue_file
	
	if file.open(dialogue_file, File.READ) == OK:
		while !file.eof_reached():
			var line = file.get_line()
			var columns = line.split(";")
			if columns.size() == 2:
				character = columns[0]
				dialogue = columns[1]
				dialog_data.append({"Character": character, "Dialogue":dialogue})
				file_already_readed = true
		file.close()
	else:
		file_already_readed = false
		print("hubo un error al tratar de leer el archivo: ", dialogue_file)
	start_dialogue()
		
	
func start_dialogue():
	animation_player.play("dialogue_enter")

func type_dialogue():
	if dialogue_label.percent_visible < 1:
		for i in range(dialogue_label.percent_visible, 1):
			dialogue_label.percent_visible += (1/character_count) * (_delta * (64^100))
			is_typing = true
			finished_typing = false

	else:
		finished_typing = true
		is_typing = false
		start_typing = false
		
func _on_AnimationPlayer_animation_finished(anim_name: String) -> void:
	if anim_name == "dialogue_enter" and !animation_finished:
		animation_finished = true
		cant_call_enter_animation = true
		start_typing_delay.start()

	if anim_name == "dialogue_exit":
		cant_call_enter_animation = false
		cant_call_exit_animation = true
		dialogue_label.bbcode_text = ""
	
func _on_start_typing_delay_timeout():
	start_typing = true

func _on_finished_typing_delay_timeout():
	start_typing = false
	finished_typing = true

How is this valid?

If not “string” equals null? scratch head

Shouldn’t that be

if _dialogue_file != null:

# or

if _dialogue_file not null:

This is the first time I see that sort of syntax in any language. Genuinely wondering if that’s valid.

It is valid syntax, though a little harder to parse:

if !(expression):

I come from unity (only a little bit) and this is how I used to do my conditionals and it works (although I should try the other 2 ifs that you mentioned), the idea is that through this if it asks if there is a file loaded (although I am realizing that I should not have asked for it this way).

Well, if the line doesn’t choke the engine I guess it’s valid, but I find it awkward and not very friendly to read.

The way I read it, it overly complicates readability.

Why do you try to do the dialog thing every frame though? I would do that in a method called when the interaction justify doing so.

Anyway, I’m going off topic.

I cant help with writing your own code but this video is very useful for simple uses

well but the main reason I opened this is because the dialog does not end until _i has the same value as dialogue_data.size() and this is where the problem arises, it turns out that the dialog ends one number before the size of dialogue_data.size() so to end the dialog you have to press the interaction key twice more.

I just woke up, so, sorry if there’s a misunderstanding on my part.

If the problem is in relation to .size(), most probably because .size() reflects the number of items but while iterating through a list, for example, you start at base 0, thus the last item is “.size() - 1”

The same way that items 0 through 7 means 8 items. Item 0 is the 1st item, item 1 is the 2nd item… item 7 is the 8th item.

I’m not trying to be condescending, btw, but some people have forgotten about this or don’t know about it.

I know it’s like that, but I can’t make _i to be 1 because it starts from the second line of the CSV file.

So if I wanted to read the file from line 1 of the CSV file (_i = 0) then it would start from line 2 because _i is 1.

although writing this to you, I came up with the idea that I can make _i be 1 and that in the CSV file there is a blank space on line 1 of the CSV file (_i = 0) so the Array reads the file, saves the data (including line 0) and so I can make _i be 1 and do a kind of fix to the problem

(edit: didn’t work)

Why not do a simple:

From that last post, wouldn’t that work?

yes it worked i just needed to move some lines, but thanks

if file_already_readed == true:
		if _i + 1 < dialog_data.size():
			
			finished_dialogue = false
			
			if Input.is_action_just_pressed("Interact"):
				
				if finished_typing:
					_i += 1
					if !interact_key_was_pressed:
						dialogue_label.percent_visible = 0
						start_typing_delay.start()
			print("a")
		else:
			finished_dialogue = true
			print("b")
			
		character = dialog_data[_i]["Character"]
		dialogue = dialog_data[_i]["Dialogue"]
		dialogue = dialogue.replace("'","")
		character_name_text.text = character
		dialogue_label.bbcode_text = dialogue
2 Likes