Code optimazation

Godot Version

4.3

suggestions

I made a script that handles dialogues with a dictionary and enums based on conditions or no conditions at all, my script works as it should, but I would like it to be more optimized if anyone has suggestions on how to make it more organized and easy to add new dialogues. the problem I’m facing is that whenever I add a new dialogue, I have to remodify other parts in the code for the flow to keep going as it is, when a new dialogue is added the flow is sometimes broken, depending on where the dialogue index is located.

extends Node2D

# Enum for dialogue keys
enum DialogueKeys { WELCOME, TEACH_MOVE, PROCEED, DISCOVER, STATIC, TRANSFORM }

@onready var player = $"../Player"
@onready var text_label = $RichTextLabel
@onready var ui_prompt = $ui_container  
@onready var plant = $"../tree"

var typing_speed: float = 0.05
var is_typing: bool = false
var char_index: int = 0  
var current_text: String = ""  
var current_dialogue_key: int = DialogueKeys.WELCOME

# flags 
var dialogue_active: bool = true  
var track_tutorial_inputs: bool = false  # Controls input tracking for the tutorial
var transform_dialogue_shown: bool = false
var static_dialogue_shown: bool = false  

var required_keys_pressed: Dictionary = {
	"left": false,
	"right": false,
	"attacking": false
}

var dialogues: Dictionary = {
	DialogueKeys.WELCOME: {
		"text": "Welcome! My name is the one. I'm glad you have arrived.\nI'm going to teach you the basics of this world and how to survive.",
		"on_finish": null
	},
	DialogueKeys.TEACH_MOVE: {
		"text": "Press the keys to move and attack.",
		"on_finish": show_ui_prompt  # Start tracking inputs here
	},
	DialogueKeys.PROCEED: {
		"text": "Great! Let's proceed with the adventure.",
		"on_finish": null
	},
	DialogueKeys.DISCOVER: {
		"text": "Oh look, there is a plant growing.\nLet's cut it out. Go and attack it.",
		"on_finish": discover_plant
	},
	DialogueKeys.STATIC: {
		"text": "dialogue text.",
		"on_finish": null
	},
	DialogueKeys.TRANSFORM: {
		"text": "look, the bush has transformed into a tree.\nkeep attacking it.",
		"on_finish": null
	}
}

func _ready() -> void:
	player.disable_inputs()
	ui_prompt.visible = false  
	start_typing_dialogue(current_dialogue_key)  

func _process(delta: float) -> void:
	# Check if the plant health is 10 and the dialogue hasn't been shown yet
	if plant.health == 10 and !transform_dialogue_shown:
		transform_dialogue_shown = true  
		plant.transform_to_tree()  

func start_typing_dialogue(key: int) -> void:
	if dialogues.has(key):
		dialogue_active = true  
		var dialogue = dialogues[key]
		start_typing(dialogue["text"])

func start_typing(text: String) -> void:
	char_index = 0
	text_label.text = text  
	text_label.visible_characters = 0  
	is_typing = true  
	current_text = text  
	_type_character()  

func _type_character() -> void:
	if is_typing and char_index < current_text.length():
		char_index += 1
		text_label.visible_characters = char_index  
		await get_tree().create_timer(typing_speed).timeout
		_type_character()  
	else:
		is_typing = false  
		handle_dialogue_finish()  

func handle_dialogue_finish() -> void:
	var dialogue = dialogues[current_dialogue_key]
	var on_finish = dialogue.get("on_finish", null)
	if on_finish and on_finish is Callable:
		on_finish.call()  
	else:
		move_to_next_dialogue()  

func move_to_next_dialogue() -> void:
	if current_dialogue_key + 1 in dialogues:
		current_dialogue_key += 1  
		start_typing_dialogue(current_dialogue_key)  
	else:
		print("All dialogues have been completed.")
		dialogue_active = false  
		track_tutorial_inputs = false  # Stop tracking inputs after tutorial

func show_ui_prompt() -> void:
	ui_prompt.visible = true  
	player.enable_inputs()  
	track_tutorial_inputs = true  # Start tracking inputs now

func discover_plant() -> void:
	plant.show_bush() 
	plant.activate_regeneration()
	print("Dialogue complete. Plant discovered and activated!")

	# Directly show STATIC dialogue immediately after DISCOVER
	if !static_dialogue_shown:
		static_dialogue_shown = true  # Prevent this from re-triggering
		start_typing_dialogue(DialogueKeys.STATIC)  # Show STATIC dialogue

func _input(event: InputEvent) -> void:
	if not dialogue_active or not track_tutorial_inputs:
		return  # Ignore inputs unless explicitly allowed

	if event.is_action_pressed("left"):
		required_keys_pressed["left"] = true
	elif event.is_action_pressed("right"):
		required_keys_pressed["right"] = true
	elif event.is_action_pressed("attacking"): 
		required_keys_pressed["attacking"] = true

	if all_keys_pressed():
		ui_prompt.visible = false  
		track_tutorial_inputs = false  # Stop tracking inputs after completion
		move_to_next_dialogue()  

func all_keys_pressed() -> bool:
	for key in required_keys_pressed.keys():
		if not required_keys_pressed[key]:
			return false
	return true

I would do the if functions like this

var plant :=

func _process(delta: float) -> void:
	if plant.health != 10 or !transform_dialogue_shown:
		return
	transform_dialogue_shown = true  
	plant.transform_to_tree()

I’m not actually sure why this is better but I picked it up from yosoyfreeman who’s quite good soooooo

this is not what im looking for, i get the optimization to do :=, in process I’m thinking return is simply making the computer have less overload on it? but anyway, this is not what I mean, I want suggestions on how I can modify my dictionary and the functions that work with it to work better, as I said, every time I add a new dialogue, the flow breaks and I got to modify the code. if there is a way to optimize the code to allow easy adding of dialogue index and they work flawlessly when the game runs, no need to change code or modify or create more flags or whatever. if that is understood better

Since your DialogueKeys are used in sequence anyways could you change your dialogues to an array and remove DialogueKeys entirely?

var dialogues: Array[Dictionary] = [
	{
		"text": "Welcome! My name is the one. I'm glad you have arrived.\nI'm going to teach you the basics of this world and how to survive.",
		"on_finish": null
	},
	{
		"text": "Press the keys to move and attack.",
		"on_finish": show_ui_prompt  # Start tracking inputs here
	},
# etc...
]

I would recommend loading dialogue as files over hard-coding dialogue within the scripts.

2 Likes

i get the optimization to do :=

What? I only did that so the autoformatting wouldn’t turn everything red
anyway
So by optimise you mean make it more modular and malleable - I’d assign each dialogue to an int, and make the code get the dialogue assigned to the int designated by the contextual player input, that way each dialogue segment would be composed of the text followed by options for what dialogue to play next, that way you could make it all flowchart style
But tbh I don’t know much about this stuff yet so listen to gertkeno