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()
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.
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.
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.
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.
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.
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
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