Queue_free not working with multiple nodes (3+)

Godot Version

4.6.2

Question

For the test, I have a loop to add n objects to the scene:

for i in range(0, 3):
		on_laying_egg_event(EggConfig.new(Vector2(919.0+i*20, 449.0+i*20), 0, 1))

After animation, “stars” should be removed by the script:

func scale_down_and_kill() -> void:
	if is_queued_for_deletion():
		return
	if _kill_tween and _kill_tween.is_valid():
		_kill_tween.kill()
	
	_kill_tween = create_tween()
	_kill_tween.parallel().tween_property($Star, "scale", Vector2(INIT_SCALE, INIT_SCALE), TWEEN_TIME_IN_S)
	_kill_tween.parallel().tween_property($Star, "rotation_degrees", 0, TWEEN_TIME_IN_S)
	
	_kill_tween.finished.connect(queue_free, CONNECT_ONE_SHOT)
	print("kill ", self)

As you can notice on the record, “kill” is always printed three times, but for some reason, “stars” are not removed.

aWliuQbwRA

The scale_down_and_kill method is called as a signal callback on egg animation end. The implementation of the callback:

func spawn_chick_and_free_egg(egg: Egg, star: Star) -> void:
	if not is_instance_valid(star):
		print("Star is not valid")
		return
	if not is_instance_valid(egg):
		print("Egg is not valid")
		star.scale_down_and_kill()
		return

	var animal: Node
	if GameState.chick_incubation_time_in_s == 0:
		animal = HenSceen.instantiate()
		animal.scale = Vector2(0.15, 0.15)
	else:
		animal = ChickSceen.instantiate()
	animal.generation = egg.generation
	animal.position = egg.sprite_position
	egg.visible = false
	egg.queue_free()
	add_object(animal)
	star.scale_down_and_kill()

Any idea what I’m doing wrong? :thinking:

[EDIT]

Change repo visibility (temporarily) to public

[EDIT]

Changed the repo to private

How are you calling spawn_chick_and_free_egg

1 Like

This would be a lot easier to debug with the full script(s) in question.

on_laying_egg_event → emit EventBus.spawn_chick signal → handle by on_spawn_chick_event

func on_spawn_chick_event(egg: Egg) -> void:
	var star := StarSceen.instantiate()
	add_object(star)
	star.z_index = 1
	star.scale_up(egg.sprite_position, spawn_chick_and_free_egg.bind(egg, star))

and the star is big enough, the callback (spawn_chick_and_free_egg) i fire

func scale_up(egg_position: Vector2, callback: Callable) -> void:
	var tween := create_tween()
	position = egg_position
	tween.parallel().tween_property($Star, "scale", Vector2(MAX_SCALE, MAX_SCALE), TWEEN_TIME_IN_S)
	tween.parallel().tween_property($Star, "rotation_degrees", 360, TWEEN_TIME_IN_S)
	tween.tween_callback(callback)

true, I made the repo temporarily public:

So the problem is showing up in the debugger. You have Error Fatigue. It’s when you have so many things popping up in your debugger, that you stop paying attention to it.

Specifically your problem is your tween calling queue_free isn’t working. The error is showing up three times in the debugger when you run the game.

E 0:00:04:216 step: Error calling method from CallbackTweener: ‘Node2D(game.gd)::spawn_chick_and_free_egg’: Cannot convert argument 1 from Object to Object.
<C++ Error> Method/function failed. Returning: false
<C++ Source> scene/animation/tween.cpp:755 @ step()

So two things:

  1. I recommend you clear up all the warnings in your debugger so that you’ll see errors when they pop up. It’ll take you 5 minutes to clear them all.
  2. It looks like this line in game.gd is causing your problem:
star.scale_up(egg.sprite_position, spawn_chick_and_free_egg.bind(egg, star))

But I’m going to let you debug it, because if you are passing callables as function arguments, then you know how to debug it. (And I don’t want to.)

Personally, I would recommend against passing callables as function arguments in GDScript, because while it’s clever, it’s difficult to debug because the errors are not that informative. A better way to handle things in GDScript is to emit() a signal and look for that signal then do something.

I did fix one of your errors in scale_down_and_kill() by doing this:

func scale_down_and_kill() -> void:
	if is_queued_for_deletion():
		return
	if _kill_tween and _kill_tween.is_valid():
		_kill_tween.kill()
	
	_kill_tween = create_tween()
	_kill_tween.parallel().tween_property($Star, "scale", Vector2(INIT_SCALE, INIT_SCALE), TWEEN_TIME_IN_S)
	_kill_tween.parallel().tween_property($Star, "rotation_degrees", 0, TWEEN_TIME_IN_S)
	
	#_kill_tween.finished.connect(queue_free, CONNECT_ONE_SHOT)
	await _kill_tween.finished
	queue_free()
	print("kill ", self)

Thanks, I was not aware of that, to be honest. It will help me a lot :slight_smile:

I don’t know why, but I was sure an error/warning would be displayed in the console tab

P.S.: I changed the repo to private

1 Like

For those curious about the cause of the problem, I discovered that the method `spawn_chick_from_egg`, which is called by the `AnimationTree`, is triggered twice. The fix turned out to be shifting the moment of calling the method from 0.85 seconds to the very end of the animation (0.9 seconds).

1 Like