Utilizing queue_free()

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

So I’ve got a node for an enemy, which I want to die after taking too much damage. Upon death, I’ve got a particle emitter with a lifetime of .6 to show the enemy has died. So after that .6 seconds, I want to call queue_free(). I thought I could just connect a one-shot timer with a time of .6 and then call queue_free() when the timer expires, but when I tried that nothing happens. I’ve got this for the timer’s code:

func _on_DeathTimer_timeout():

I’ve tried calling queue_free() from anywhere else in the enemy’s code, like when it takes damage or collides, and it gets removed just fine. So what have I done wrong that it isn’t being removed upon expiration of the timer?

Are you using a signal to do this?

ejricketts | 2021-01-15 22:24

where is this piece of code located?
have you correctly started the timer?

Andrea | 2021-01-16 13:06

yes, originating from the death timer.

ItzZac | 2021-01-17 07:34

here is the full code, taken from the node of the enemy I’m trying to queue_free

extends KinematicBody2D

const MAX_SPEED = 50
const MAX_HEALTH = 50
const GRAVITY = 20
const FLOOR = Vector2(0, -1)

var cave_mite = self
var motion = Vector2.ZERO
var direction = 1
var dead = false
var health = 20

Called when the node enters the scene tree for the first time.

func _ready():

func damage_basic():
if health >= 10:
health -= 10
$Damage.emitting = true

func _physics_process(delta):
if dead == false:
if motion.x != 0:
motion.x = MAX_SPEED * direction
motion.y += GRAVITY
motion = move_and_slide(motion, FLOOR)
if direction == 1:
$Sprite.flip_h = false
$Sprite.flip_h = true
if is_on_wall():
direction = direction * -1
$RayCast2D.position.x *= -1
if $RayCast2D.is_colliding() == false:
direction = direction * -1
$RayCast2D.position.x *= -1
elif dead == true:
$Death.emitting = true
$CollisionShape2D.disabled = true

if health <= 0:
	dead = true

func _on_Hitbox_body_entered(body):
if “Hermit” in body.name:
body.damage = 10

func _on_DeathTimer_timeout():

ItzZac | 2021-01-17 07:35

ive been trying to figure out how to properly link that code for a minute now, but it’s quite late and I’m too tired to keep trying, ill be back to fix it tomorrow.

ItzZac | 2021-01-17 07:37

The way this is set up has it so when your enemy dies, the timer starts and has it delete itself once the given time has passed.

From what I can see, the emitter is a child of your enemy, so when you call queue_free() you are removing both the enemy and all its children, i.e., the emitter gets removed also.

It would be worth trying to create a new scene which comprises only of the emitter, and upon death of the enemy, instance the emitter to the world scene at the position of the player. Have a look at the section called Instancing Scenes, and you should be fine:

ejricketts | 2021-01-17 08:54

it’s honestly hard to read the code, next time use the {} button (in the comment editor) to make ti look better.
anyway, the problem might be in the tree configuration as ejricketts wrote.

try to add print() to debug your code, for example

elif dead == true:
 $Death.emitting = true
 $CollisionShape2D.disabled = true


func onDeathTimertimeout():

does it print anything?

Andrea | 2021-01-17 11:07

thanks both of you! I finally got it working after I some trial and error. I tried using prints to check which parts of my code were firing when, and that actually helped me resolve some issues I was having in other scripts as well. Also instancing the particle emitter rather than having it attached to the enemy was just what I needed to get that bit of code working how I want. Thanks again everybody :slight_smile:

ItzZac | 2021-01-22 03:14

No problem, glad to help!

ejricketts | 2021-01-22 15:57