Help with my Dialogue System being used with multiple characters

Godot Version

4.3-stable_linux.x86_64

Question

` I’ve attempted to make my own dialogue system in my 2d platformer. I tried to design it to be fairly flexible. Seeing as all of the dialogue would have accompanying animated sprites with variable names, I based it around using get_parent().name, and making a single area 2d called “DialogueInteraction”. I’d give the animated sprite a name, then set “DialogueInteraction” as the child, then use get_parent().name to find the name of the animated sprite, then match that name to a parsed JSON file, which would then realy the text.

Unfortunately I’ve encountered a problem with this system where get_parent().name causes every instance of the DialogueInteraction to name it’s parent, then the text displayer loads all of them and just shows whichever one came last. I’ve attempted to find ways to only get one name, like calling the get_parent.name only when the area is entered, which looks like it should work when I use print(get_parent.name) but then breaks as soon as it’s actually run.

If anyone has a solution for me I’d greatly appreciate it. This is my first project where I’m actually trying to do it without relying on any tutorials, and only using my own old tutorial projects to reference code, and it’s been going pretty alright until now. `

DialogueInteraction:

Example of how DialogueInteraction is used:

DialogueInteraction Code:

class_name Dialogue_interaction extends Area2D

@onready var animated_sprite_2d: AnimatedSprite2D = $AnimatedSprite2D

var current_name : String

func _on_area_entered(area: Area2D) -> void:
	DialogueBox.chat_zone = true
	animated_sprite_2d.show()
	pass

func _on_area_exited(area: Area2D) -> void:
	print(current_name)
	DialogueBox.chat_zone = false
	animated_sprite_2d.hide()


func _process(delta: float) -> void:
	if Input.is_action_just_pressed("Interact") and DialogueBox.chat_zone == true:
		interact_pressed()
	else:
		pass
	

func interact_pressed() -> void:
	DialogueBox.UpdateDialogue(get_parent().name)
	
	pass

This is the code that runs the actual dialogue:

class_name Dialogue_Box extends CanvasLayer

signal dialogue_finished

@export_file("*.json") var d_file
#@onready var portrait = $Dialogue/NinePatchRect/HBoxContainer/Portrait

@onready var chat: RichTextLabel = $Dialogue/Chat

const DIALOGUE_INTERACTION = preload("res://Dialouge/dialogue_interaction.tscn")
var is_active : bool = false

var dialogue_interaction : Dialogue_interaction
var chat_zone : bool = false
var current_dialogue_id = -1

var dialogue_choice = []
var chat_name

@onready var dialogue: Control = $Dialogue


func _ready() -> void:
	current_dialogue_id = -1
	hide_dialogue()
	pass

func start():
	chat.visible_ratio = 0
	current_dialogue_id = -1
	if is_active:
		return
	is_active = true
	show_dialogue()
	
		
func _process(delta: float) -> void:
	#print(chat.visible_ratio)
	chat.visible_ratio += 0.05
	
	
func _unhandled_input(event : InputEvent) -> void:
	#if is_active == false:
		#return
	if event.is_action_pressed("Interact") and chat_zone == true and GlobalPlayerManager.player.is_on_floor():
		
		#print(len(dialogue_choice))
		#print(current_dialogue_id)
		if is_active == false:
			show_dialogue()
		if is_active == true:
			if current_dialogue_id >= len(dialogue_choice) - 1 and chat.visible_ratio == 1:
				current_dialogue_id = -1
				hide_dialogue()
			else:
				if chat.visible_ratio == 1:
					current_dialogue_id += 1
					chat.visible_ratio = 0
	
	pass

func UpdateDialogue(npcname : String) -> void:
	#chat.visible_characters = 0
	dialogue_choice = load_dialogue(npcname)

		
	$Dialogue/Name.text = chat_name
	$Dialogue/Chat.text = dialogue_choice[current_dialogue_id]['chat']
	

func show_dialogue() -> void:
	is_active = true
	dialogue.visible = true
	dialogue.process_mode = Node.PROCESS_MODE_ALWAYS
	get_tree().paused = true
	pass
	
func hide_dialogue() -> void:
	is_active = false
	dialogue.visible = false
	dialogue.process_mode = Node.PROCESS_MODE_DISABLED
	get_tree().paused = false
	pass

func load_dialogue( npcname : String ):
	if npcname == "Shopkeep":
		chat_name = "Shopkeep"
		var file = FileAccess.open("res://Dialouge/npc_dialogue/shopkeep/1.json", FileAccess.READ)
		var content = JSON.parse_string(file.get_as_text())
		print (content)
		return content
	if npcname == "Blah":
		chat_name = "Shopkeep"
		var file = FileAccess.open("res://Dialouge/npc_dialogue/shopkeep/2.json", FileAccess.READ)
		var content = JSON.parse_string(file.get_as_text())
		print (content)
		return content
	pass
	

Are you sure it’s name is changing? If it’s loading all of the dialogue I think the more likely issue is that your _on_area_entered function does not check what entered, so it will trigger for even static bodies like the floor or walls, thus pressing “Interact” triggers every dialogue overlapping a floor.

No it’s good, I’ve got specified layers for the different collision types, also it’s not on the floor or in contact with any other physics objects. Everything activates exactly when it’s supposed to, just not how it’s supposed to.

Also I set up a print function that gets the ‘get_player().name’ and prints it to the output whenever the player walks into or out of a dialogue area, and that’s always accurate to the correct area, but when attempting to put it through the code, it doesn’t work.


The character with the purple hair in the middle, and the godot logo to the right, both have the dialogue box as a child, and aren’t touching anything.

I also have an effect where a exclamation mark appears above their head when you get within range.

Maybe it’s this line? You are setting a global variable DialogueBox.chat_zone to true, thus globally every chat zone is true and ready to interact. Try changing chat_zone to a local variable.

As an optimization you can move this to _unhandled_input

func _unhandled_input(event: InputEvent) -> void:
	if event.is_action_pressed("Interact") and chat_zone:
		interact_pressed()
2 Likes

Exceptional find my friend! That’s exactly what I was looking for, didn’t even occur to me that they were all running because it was global, nice catch! Thanks for the help.


always there to help me apparently lol. Specifically on chat related stuff, the first reply even was the thing that worked last time.

1 Like