Instantiated scene and different script

Godot Version

v4.3.stable.official [77dcf97d8]

Question

Hello guys,

My name is lean, i’m a solo dev and i’m struggling with a problem.

Let me try to be clear, I created a dialogue system in a control scene, works well, the problem is other.

I have another scene where i wanna instantiate this dialogue system, but i don’t want that instantiate scene plays when the original scene starts, i have a animation player on my scene, i wish i could make that instantiate scene only play when this animation come along, and i don’t know how to do that.

I already tried a lot of things and nothing seems to work, and this is not the only problem. I don’t want that instantiate scene inherit the script from the original, so i already tried to remove the script and attached a new one, but no matter what i do, seems like the script from the original scene always load and the new one don’t. Probably i’m doing a lot of wrong things, that’s why i’m asking for help, can anyone lend me a hand? :wink:

Could you show some of your instantiating script? If your extended script overrides the _ready() function then it won’t run on the base script. For a dialogue system maybe it would be good to use a Global/Singleton?

1 Like

Hey, thanks for replying. I think you just clear my mind, i did know about singleton, but i didn’t though i should use my dialogue system like one, what a shame.

I think the best thing is recreate my dialogue system in this mode(singleton/global)

i could put my script here but i’ll save your time, because you already saved me. If i have any problems in a future, could i hit you up? i’m really in need solodev friends.

1 Like

Hey i tried to do what you said, but when i make my dialogue system scene global(autoload), i get a lot of errors, somethings like can’t acess the nodes from the scene.

Can you lend me a hand one more time? here’s my actual code without be global(autoload);

extends Control

List of dialogues

@export var dialogue_texts: Array = [
“hello.”,
“how are you?”,
“what’s your name?”
]

Current line index

var current_line: int = 0

Animation control

var is_animating: bool = false

@export var typing_speed: float = 0.05

References to the nodes

@onready var dialogue_label = $Panel/Label # Correctly points to the Label
@onready var audio_player = $AudioStreamPlayer2D

Dynamically created timer

var typing_timer: Timer = null

Current full text being animated

var current_text: String = “”

Current character index

var char_index: int = 0

Script initialization

func _ready():
self.visible = false
show_dialogue() # Show the dialogue at the start

Updates the text on the Label based on the current index

func display_current_line():
if current_line < dialogue_texts.size():
animate_text(dialogue_texts[current_line])
play_typing_sound()
else:
hide_dialogue()

Method to handle key press

func _input(event):
if event.is_action_pressed(“ui_accept”): # Detects the pressing of the “Space” key (or Enter, depending on input settings)
if is_animating:
skip_animation() # Skips the animation
else:
current_line += 1
if current_line < dialogue_texts.size():
display_current_line()
else:
hide_dialogue() # Hides the dialogue when it ends

Shows the dialogue panel and restarts the dialogue

func show_dialogue():
self.visible = true
current_line = 0
display_current_line()

Hides the dialogue panel

func hide_dialogue():
self.visible = false
stop_typing_sound()

Animates the text by displaying one character at a time

func animate_text(full_text: String):
if typing_timer:
typing_timer.queue_free()
is_animating = true
current_text = full_text
dialogue_label.text = “”
char_index = 0
typing_timer = Timer.new()
typing_timer.wait_time = typing_speed
typing_timer.one_shot = false
add_child(typing_timer)
typing_timer.start()
typing_timer.timeout.connect(Callable(self, “add_character”))

Adds a character to the animated text

func add_character():
if char_index < current_text.length():
dialogue_label.text += current_text[char_index]
char_index += 1
else:
is_animating = false
stop_timer()
stop_typing_sound()

Skips the animation and displays the full text

func skip_animation():
if typing_timer:
stop_timer()
is_animating = false
dialogue_label.text = current_text
stop_typing_sound()

Stops and removes the timer

func stop_timer():
if typing_timer:
typing_timer.stop()
typing_timer.queue_free()
typing_timer = null

Plays the typing sound

func play_typing_sound():
var sound = load(“res://sounds/scripttextsound.wav”)
if sound:
audio_player.stream = sound
audio_player.play()

Stops the typing sound

func stop_typing_sound():
if audio_player.is_playing():
audio_player.stop()

What are the exact error messages?

Can you format your code paste?

1 Like

Oh sorry, didn’t about that, here’s my code like a autoload;

@export var dialogue_texts: Array = [
	"Hello.",
	"how are you?",
	"what's your name?"
]

# Current dialogue index
var current_line: int = 0

# Animation control
var is_animating: bool = false

@export var typing_speed: float = 0.05

# References for the nodes
@onready var dialogue_label = $Panel/Label  # Correctly point to the Label
@onready var audio_player = $AudioStreamPlayer2D

# Dynamically created timer
var typing_timer: Timer = null

# Full text currently being animated
var current_text: String = ""

# Current character index
var char_index: int = 0

# Defining the dialogue finished signal
signal dialogue_finished

# Script initialization
func _ready():
	self.visible = false
	show_dialogue()  # Show the dialogue when starting

# Updates the text in the Label based on the current index
func display_current_line():
	if current_line < dialogue_texts.size():
		animate_text(dialogue_texts[current_line])
		play_typing_sound()
	else:
		hide_dialogue()

# Method to handle key presses
func _input(event):
	if event.is_action_pressed("ui_accept"):  # Detects pressing the "Space" key (or Enter, depending on input settings)
		if is_animating:
			skip_animation()  # Skips the animation
		else:
			current_line += 1
			if current_line < dialogue_texts.size():
				display_current_line()
			else:
				emit_signal("dialogue_finished")
				hide_dialogue()

# Shows the dialogue panel and restarts the dialogue
func show_dialogue():
	self.visible = true
	current_line = 0
	display_current_line()

# Hides the dialogue panel
func hide_dialogue():
	self.visible = false
	stop_typing_sound()

# Animates the text by displaying one letter at a time
func animate_text(full_text: String):
	if typing_timer:
		typing_timer.queue_free()
	is_animating = true
	current_text = full_text
	dialogue_label.text = ""
	char_index = 0
	typing_timer = Timer.new()
	typing_timer.wait_time = typing_speed
	typing_timer.one_shot = false
	add_child(typing_timer)
	typing_timer.start()
	typing_timer.timeout.connect(Callable(self, "add_character"))

# Adds a letter to the animated text
func add_character():
	if char_index < current_text.length():
		dialogue_label.text += current_text[char_index]
		char_index += 1
	else:
		is_animating = false
		stop_timer()
		stop_typing_sound()

# Skips the animation and displays the full text
func skip_animation():
	if typing_timer:
		stop_timer()
	is_animating = false
	dialogue_label.text = current_text
	stop_typing_sound()  # Stops the typing sound when skipped

# Stops and removes the timer
func stop_timer():
	if typing_timer:
		typing_timer.stop()
		typing_timer.queue_free()
		typing_timer = null

# Plays the typing sound
func play_typing_sound():
	var sound = load("res://sounds/scripttextsound.wav")
	if sound:
		audio_player.stream = sound
		audio_player.play()

# Stops the typing sound
func stop_typing_sound():
	if audio_player.is_playing():
		audio_player.stop()

and i get this error;

Invalid assignment of property or key ‘text’ with value of type ‘String’ on a base object of type ‘null instance’.

at the line;

dialogue_label.text = ""

If you added the script .gd as a Autload then it won’t create any children, make sure you add the scene .tscn as Autoload/Global

1 Like

if i do this, i don’t get any errors but the DialogueSystem simple doesn’t appear on the scene, i don’t know why.

I tried to create a scene just for testing, like i said i don’t get any erros, but all black, here’s the code of my test scene;


func _ready() -> void:
	# Chama o autoload para mostrar a transição
	if DialogueSystem:
		DialogueSystem.show_dialogue()  # Chama o autoload do diálogo
		
		var transition_timer = Timer.new()
		transition_timer.wait_time = 2.0  
		transition_timer.one_shot = true
		add_child(transition_timer)
		transition_timer.start()

		transition_timer.timeout.connect(Callable(self, "_on_transition_complete"))

func _on_transition_complete():
	if DialogueSystem:
		DialogueSystem.show_dialogue()  

It may be added behind other 2D nodes? you may also have to add a CanvasLayer as the root node, with a higher layer than the default. Hard to say without knowing your Scene tree for either the dialogue or the test scene

So, i edit my DialogueSystem, my scene tree look like this;

DialogueSystem (CanvasLayer)
Control (child from canvas) with a script
Panel (child from control)
TextureRect (child from panel)
Label (child from panel)
AudioStreamPlayer2D (child from panel)

ths script on the control is that one;


@export var dialogue_texts: Array = [
    "Hello.",
    "Sorry",
    "Be honest."
]

var current_line: int = 0
var is_animating: bool = false

@export var typing_speed: float = 0.05

@onready var dialogue_label = $Panel/Label  # Make sure the path to the Label is correct
@onready var audio_player = $AudioStreamPlayer2D
@onready var texture_rect = $Panel/TextureRect  # If needed for background animation, for example

var typing_timer: Timer = null
var current_text: String = ""
var char_index: int = 0

signal dialogue_finished

# Function to show the dialogue
func show_dialogue():
    self.visible = true
    current_line = 0
    display_current_line()

# Function to display the current line of dialogue
func display_current_line():
    if current_line < dialogue_texts.size():
        animate_text(dialogue_texts[current_line])
        play_typing_sound()
    else:
        hide_dialogue()

# Method to handle key press
func _input(event):
    if event.is_action_pressed("ui_accept"):  # Detects the pressing of the "Space" or Enter key
        if is_animating:
            skip_animation()  # Skip the animation
        else:
            current_line += 1
            if current_line < dialogue_texts.size():
                display_current_line()
            else:
                emit_signal("dialogue_finished")
                hide_dialogue()

# Hides the dialogue panel
func hide_dialogue():
    self.visible = false
    stop_typing_sound()

# Animates the text by displaying one letter at a time
func animate_text(full_text: String):
    if typing_timer:
        typing_timer.queue_free()
    is_animating = true
    current_text = full_text
    dialogue_label.text = ""  # Clears the label text before starting
    char_index = 0
    typing_timer = Timer.new()
    typing_timer.wait_time = typing_speed
    typing_timer.one_shot = false
    add_child(typing_timer)
    typing_timer.start()
    typing_timer.timeout.connect(Callable(self, "add_character"))

# Adds one character to the animated text
func add_character():
    if char_index < current_text.length():
        dialogue_label.text += current_text[char_index]
        char_index += 1
    else:
        is_animating = false
        stop_timer()
        stop_typing_sound()

# Skips the animation and displays the full text
func skip_animation():
    if typing_timer:
        stop_timer()
    is_animating = false
    dialogue_label.text = current_text
    stop_typing_sound()

# Stops and removes the timer
func stop_timer():
    if typing_timer:
        typing_timer.stop()
        typing_timer.queue_free()
        typing_timer = null

# Plays the typing sound
func play_typing_sound():
    var sound = load("res://sounds/scripttextsound.wav")
    if sound:
        audio_player.stream = sound
        audio_player.play()

# Stops the typing sound
func stop_typing_sound():
    if audio_player.is_playing():
        audio_player.stop()

# When the scene is loaded
func _ready():
    # Checks if the Label is found correctly
    if dialogue_label == null:
        print("Error: The Label was not found!")
    else:
        print("Label found correctly!")

but no matter what i still getting this error at this line;

dialogue_label.text = “”

Invalid assignment of property or key ‘text’ with value of type ‘String’ on a base object of type ‘null instance’.

How about adding these lines to _ready()? Can you tell me what they print?

func _ready():
    print(get_path())
    print_tree()

“Error: The Label was not found!
/root/DialogueSystem”

also in the errors i get;

node not found
Panel/Label
AudioStreamPlayer2D
Panel/TextureRect

relative to /root/DialogueSystem

Don’t know why, because everything is on the scene

Seems like the same issue here, add the scene.tscn as a Global, not the script.gd; otherwise it won’t have any children.

When i do this (use tscn on global), i get the error about text “” seems like a eternal cycle, i really don’t get, sorry! Could you create a scene like mine and test? so we can see if you get the same errors? if not, probably i did really something wrong.

The error states that dialogue_label is null, since that’s what you are using .text on and assigning a empty ("") String value to. This means it cannot find $Panel/Label, I had assumed it was because of the Global but I guess that path doesn’t check out in the scene either. Can you share a screenshot of your scene tree?

print_tree() should print all of the children and descendants of the scene, but it seems like it isn’t printing any children, paired with the path being at /root/ leads me to belive the script was added as global. That’s my reasoning for thinking it’s still a script added as Global instead of the scene, assuming you did copy the output panel exactly.

Here’s a print from my scene, you know? i think i’ll create a new project and make everything again from zero, cause i really don’t know what’s going on.

Keep the DialogueSystem node as the scene root since it has the script, only change it’s type and the script’s extends to CanvasLayer. You probably want a AudioStreamPlayer, not an AudioStreamPlayer2D

The Globals looks correct other than that. Do you get a different error message? Maybe a screenshot of your stack trace/output panel would be more helpful. I worry starting over may run into the same issues.

1 Like

Dude, finally worked! i just did what you said, delete the control node, and i’m only using a CanvasLayer now, atached the script and extends on the code, and now works, thank you a lot!

The only problem i get now is that DialogueSystem(autolado) appear in every scene that i create, i mean if i create a new scene and plays, the DialogueSystem appears too, don’t know why, maybe something on ready function on autoload? see the new code working

extends CanvasLayer

# List of dialogues
@export var dialogue_texts: Array = [
	"hello.",
	"how are you?",
	"what’s your name?"
]

# Current line index
var current_line: int = 0

# Animation control
var is_animating: bool = false

# Typing speed
@export var typing_speed: float = 0.05

# References for the nodes
@onready var dialogue_label = $Panel/Label  # Correctly points to the Label
@onready var audio_player = $Panel/AudioStreamPlayer  # Points to the audio player

# Dynamic timer created for the typing animation
var typing_timer: Timer = null

# Full text that is being animated
var current_text: String = ""

# Current character index
var char_index: int = 0

# Script initialization
func _ready():
	self.visible = false  # Initially, the dialogue panel is invisible
	show_dialogue()  # Shows the dialogue as soon as the game starts

# Updates the text in the Label based on the current index
func display_current_line():
	if current_line < dialogue_texts.size():
		animate_text(dialogue_texts[current_line])  # Animates the current text
		play_typing_sound()  # Plays the typing sound
	else:
		hide_dialogue()  # Hides the dialogue panel if all dialogues have been displayed

# Method that handles player input (keyboard)
func _input(event):
	if event.is_action_pressed("ui_accept"):  # Detects when the "Space" or "Enter" key is pressed
		if is_animating:
			skip_animation()  # If animation is running, skip to the end
		else:
			current_line += 1  # Advances to the next dialogue
			if current_line < dialogue_texts.size():
				display_current_line()  # Displays the next dialogue
			else:
				hide_dialogue()  # Hides the dialogue panel when all dialogues are finished

# Displays the dialogue panel and restarts the dialogue
func show_dialogue():
	self.visible = true  # Makes the panel visible
	current_line = 0  # Resets the line index
	display_current_line()  # Displays the first dialogue

# Hides the dialogue panel
func hide_dialogue():
	self.visible = false  # Makes the panel invisible
	stop_typing_sound()  # Stops the typing sound

# Animates the text, displaying one character at a time
func animate_text(full_text: String):
	if typing_timer:
		typing_timer.queue_free()  # If there is already a timer, frees the previous one
	is_animating = true  # Marks that the animation is ongoing
	current_text = full_text  # Sets the full text that will be animated
	dialogue_label.text = ""  # Clears the previous text
	char_index = 0  # Resets the character index
	typing_timer = Timer.new()  # Creates a new timer
	typing_timer.wait_time = typing_speed  # Sets the typing interval
	typing_timer.one_shot = false  # The timer repeats
	add_child(typing_timer)  # Adds the timer as a child of the current node
	typing_timer.start()  # Starts the timer
	typing_timer.timeout.connect(Callable(self, "add_character"))  # Connects the timeout event to the add_character method

# Adds a character to the displayed text
func add_character():
	if char_index < current_text.length():
		dialogue_label.text += current_text[char_index]  # Adds the next character
		char_index += 1  # Advances to the next character
	else:
		is_animating = false  # Marks that the animation is finished
		stop_timer()  # Stops the timer
		stop_typing_sound()  # Stops the typing sound

# Skips the animation and displays the full text
func skip_animation():
	if typing_timer:
		stop_timer()  # Stops the timer
	is_animating = false  # Marks that the animation was skipped
	dialogue_label.text = current_text  # Immediately shows the full text
	stop_typing_sound()  # Stops the typing sound

# Stops and removes the timer
func stop_timer():
	if typing_timer:
		typing_timer.stop()  # Stops the timer
		typing_timer.queue_free()  # Frees the timer
		typing_timer = null  # Sets the timer to null

# Plays the typing sound
func play_typing_sound():
	var sound = load("res://sounds/scripttextsound.wav")  # Loads the sound
	if sound:
		audio_player.stream = sound  # Sets the sound in the audio player
		audio_player.play()  # Plays the sound

# Stops the typing sound
func stop_typing_sound():
	if audio_player.is_playing():  # Checks if the audio is playing
		audio_player.stop()  # Stops the audio playback

That is exactly what Autoload is for, it creates the specified scene once, for everywhere

1 Like

Yes, sorry!(noob question)

I just declared a hide function, so I can use it to avoid this, right? works well btw

So i guess i can handle things by now, thank you a lot for your patience and help!

1 Like