_ready() not working in an instanced object?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Irolan

Hello,
I’m trying to create an explosion that is to be spawned in after an enemy dies.
The explosion is a Node2D object and comprises an animated sprite “ExplosionSprite”, an audio stream “SoundExplosion01” and a timer “DeathTimer”.

Here is the code for spawning the explosion. It is executed within the enemy.

export (PackedScene) var death #the explosion is a scene, placed here
var health = 5

func enemy_handle_hit(): #this is triggered when a bullet hits the enemy
	health -= 3
	if health <= 0:
		var explosion = death.instance()
		add_child(explosion)
		queue_free()

This is the code of the explosion:

extends Node2D

onready var explosion_sprite = $ExplosionSprite
onready var explosion_sound = $SoundExplosion01
onready var death_timer = $DeathTimer

func _ready():
	print(str(get_global_position().x, ", ", get_global_position().y)) #debug
	death_timer.start()
	explosion_sprite.play()
	explosion_sound.play()

func _on_DeathTimer_timeout():
	print("dead") #debug
	queue_free()

So here’s what happens: the explosion spawns in and the print() under _ready() is called and provides the proper coordinates. However, the timer does not start and neither the sprite nor the audio ever play.
Also, when I set timer, sprite or audio to autoplay in the Inspector, they never start either when the scene is instanced. However, when I play the actual scene using the “Play Scene” button, it works fine.
Before anyone asks, the on_DeathTimer_timeout() is connected, but even if it wasn’t, the sprite and audio should play nontheless.
There is no error logged, it’s just like the thing is ignoring the start() and play() commands.

What is also weird, I have another object extending Area2D that also starts a timer in _ready() and that works fine.
Is it different with Node2D? Do I need to do that stuff in another function?

:bust_in_silhouette: Reply From: thadiusII

It looks like it’s because the enemy is calling queue_free() to fast for the explosion to be able to happen. To solve this you could use get_parent().add_child() instead of just add_child(). Alternatively, you could have a timer the length of the explosion and call queue_free() when it times out.

Oh… my god… I never considered that if I delete an object, the child objects get deleted as well. Wow, I am such an idiot.
get_parent().add_child() is the solution.
Thanks thadiusII!

Irolan | 2021-09-11 19:42