Queue_free() seems to not work randomly

Godot Version

Godot 4.2.1

Question

I set up a simple Atari Breakout game. One bug remains unsquashed now - sometimes bricks don’t go away after getting hit. Here’s my GDScript code for the bricks:

extends StaticBody2D

func hit():
	queue_free()
	print("hit")

And my code for the ball:

extends RigidBody2D

@export var speed = 250.0
var direction 

func _ready():
	direction = Vector2(1,1)
	
func _process(delta):
	position += direction * speed * delta
	
	
func _physics_process(delta):
	var collision = move_and_collide(direction * delta)
	if collision:
		var reflect = collision.get_remainder().bounce(collision.get_normal())
		direction = direction.bounce(collision.get_normal())
		move_and_collide(reflect)
		
		if collision.get_collider().is_in_group("block"): # Check if collided with a brick
			collision.get_collider().hit()
			print("COLLIDED WITH BLOCK") # put this here for testing

func _on_visible_on_screen_notifier_2d_screen_exited():
	get_tree().reload_current_scene()

So what happens when I run the game is, sometimes bricks that get hit by the ball get queue_free’d, like it’s meant to, and sometimes they don’t. I put print statements in the if collision.get_collider().is_in_group("block"): and hit() sections to make sure that those lines are actually being executed, and they are. Apparently the hit() function is successfully executed every time a brick gets hit by the ball, but sometimes the queue_free() just doesn’t work. I couldn’t find a pattern to it. queue_free() just seems to not work randomly.

If anyone could tell me what went wrong, I’d be very grateful.

I would guess that queue_free() is not instant *

Hide the node (visible = false) just before you queue_free it. Maybe?

Why wouldn’t queue_free be instant? Is it due to some inherent stuff of the engine itself?

Also, I tried adding visible = false before queue_free(), but no luck. :frowning:

If you want the node to be eviscerated immediately, try Node.free(). This should kill it at that moment.

I think what Node.queue_free() does is “queue” the removal before the next available frame is called. I assume this is so relevant processes can finish processing and don’t have to worry about the thing they were processing disappearing mid-process.

by hiding it, I meant that at least it won’t be in the way and can free when the queue gets to it.