Enemy dies the CollisionShape2D stays!

Godot Version

Godot v4.3

Question

So when I kill an enemy, he dies but its CollisionShape2D stays in the game how to remove it alongside the sprite?

I have something like this for enemy script

func enemy_hit():
	health -= 1
	if health == 0:
		sprite_2d.animation = "explosion"


func _on_sprite_2d_animation_finished() -> void:
	if health == 0:
		sprite_2d.animation = "explosion"
		queue_free()

can you show us your scene tree?

1 Like

this?

1 Like

yes, however that’s weird.

i want you to use animationPlayer node instead of sprite2D, hope it’ll fix

2 Likes

Hi!

Are you sure the queue_free() line is called correctly? Seeing your scene, it would definitely work fine, so I’m wondering if the problem is not related to the function just not being called.
Add a print('queue free') line before, and make sure the print shows up in the console. If not, that means the node is not freed at all, hence the collision still being there. The animation is just an animation, so your enemy may look like it died, but its node is still here, and its collision does not care about its animation.

1 Like

You are right!

it’s something to do here
i think

func enemy_hit():
	health -= 1
	if health == 0:
		sprite_2d.animation = "explosion"

i need to queue_free() both the animation after it finish and the node
but how to do that?

if i try this

func enemy_hit():
	health -= 1
	if health == 0:
       queue_free()
		sprite_2d.animation = "explosion"

both may remove but without the animation been played
that’s a problem

shouldn’t there be something like


get_node("CollisionShape2D").disabled = true 

I did this but not working there must be something wrong

func enemy_hit():
	health -= 1
	if health == 0:
		sprite_2d.animation = "explosion"
        get_node("CollisionShape2D").disabled = true 

func _on_sprite_2d_animation_finished() -> void:
	if health == 0:
		sprite_2d.animation = "explosion"
		queue_free()

Glad my guess was correct!

You could try something like this:

func enemy_hit():
    health -= 1
    if health == 0:
        # Play anim and disable collision
        sprite_2d.animation = "explosion"
        get_node("CollisionShape2D").disabled = true

        # Wait for an arbitrary delay (long enough for the animation to play)
        await get_tree().create_timer(2.0).timeout

        # Actual node destruction
        queue_free()

This way, you play the animation, disable the collision to avoid any detection issue, and after a short delay, you free the node.

:warning: Please note that this is just a workaround, the proper solution would be to detect the animation is done playing to free the node (sadly I’ve never done that, it may be easy but I just don’t know that off the top of my head).
An issue you may have with my solution is that if you change the animation duration, you’d have to also update the code, which is very unconvenient. But I guess it would work for prototyping!
Let me know.

1 Like

Hi, maybe call the “func _on_sprite2d_animation_finished()” in the func enemy_hit()? Like:

Because i don’t think that function is built in Sprite2Ds in godot

1 Like

Hi, you should not be using an AnimatedSprite2D, this is a complex character with probably more than 2 animations, and that’s causing problems because you don’t have a state machine.

How many enemies have to be on screen at the same time?

if there’s like around 100 enemies or less, use a Sprite2D with AnimationPlayer and an AnimationTree instead of AnimatedSprite.

an AnimationTree can use a statemachine and you can set a one way path for when the enemy dies.

idle->die

it will also greatly simplify your code and do transitions automatically.

if there needs to be hundreds of enemies on screen, I don’t know about the performance of AnimatedSprite2D, but you do need some kind of state machine to control the animations.

1 Like

What’s wrong with AnimatedSprite2D? They work fine for me, Is that node a noob node

AnimatedSprite2D has its uses, but for a character it has many problems:

  • no integration with AnimationTree, and it can’t be converted to AnimationPlayer. this means that you are locked if you need some other feature. it also means that a state machine has to be manually created and managed.
  • it also has no transitions, and can only animate itself.
  • no control over the center of the sprite, which is important for flipping the sprite. also each frame can be a different image with different size, which complicates this more.

AnimatedSprite2D is good for something like an explosion, that is simple and has to run once, or a box that animates constantly and is then hit by the player turning it into something different.

for a player or enemy it is always best to use a Sprite2D with AnimationPlayer, and even better with an AnimationTree.

2 Likes

Hi, i have a question, Animatedsprite2ds can use spritesheets, So how can it change sizes? And my aninatedsprites can flip too, so what’s wrong with it flipping?

I have another question, Do you watch inbound shovel? If you do, does he use Sprite2Ds for hos game and not animatedsprite2d? His game looks really nice

Thanks

1 Like

Hi, maybe call the “func _on_sprite2d_animation_finished()” in the func enemy_hit()?

func enemy_hit():
	health -= 1
	if health == 0:
		sprite_2d.animation = "explosion"
        _on_sprite_2d_animation_finished()


func _on_sprite_2d_animation_finished() -> void:
	if health == 0:
		sprite_2d.animation = "explosion"
		queue_free()

I did this both got removed and the animation not playing

1 Like

Hmmm… i’ll check…

1 Like

Thanks to all of you, problem is solved!

I did this and it worked

func enemy_hit():
	health -= 1
	if health == 0:
		sprite_2d.animation = "explosion"
		await get_tree().create_timer(1.0).timeout
		queue_free()
		
		
		
func _on_animated_sprite_2d_animation_finished() -> void:
	if health == 0:
		sprite_2d.animation = "explosion"
		await get_tree().create_timer(1.0).timeout
		queue_free()
1 Like