What happens is that the enemy, instead of playing the death animation, what happens is that the enemy does not die and somehow replaces the attack animation with the death animation. Please help.
code
extends CharacterBody2D
@export var movement_speed = 50
@onready var planta = get_tree().get_first_node_in_group("planta")
@onready var sprite = $Sprite2D
@onready var vida = 20
@onready var flash = $hitflash
func _physics_process(_delta):
if is_instance_valid(planta):
var direction = global_position.direction_to(planta.global_position)
velocity = direction*movement_speed
move_and_slide()
if direction.x > 0:
sprite.flip_h = false
elif direction.x < 0:
sprite.flip_h = true
else:
planta = get_tree().get_first_node_in_group("planta")
move_and_slide()
func _ready():
$lil.play("move")
func _on_area_2d_area_entered(_area):
if _area.is_in_group("planta_area"):
$lil.play("attack")
elif _area.is_in_group("bala"):
flash.play("hit_flash")
vida -= 9
if vida <= 0:
$lil.play("ded")
await $lil.animation_finished
This isn’t a lot of info to go on, but I’ll give any specific help I can and a general debugging suggestion.
I’d make sure you’re code reaches the play("ded") block. Add a break point and go through and check if it does. Alternatively you can add prints to see as well.
If you look at the structure of the code in the _on_area2d_area_entered()(assuming some stuff since I don’t know the words due to language). Whenever the function is called upon signal emittance, you are probably calling play() more than once in one function. This is because there are two if statements which can be corrected by restructuring and consolidating it into a single if/else.
func _on_area_2d_area_entered(_area):
if vida <= 0:
$lil.play("ded")
await $lil.animation_finished
queue_free() # OPT - Queues the entity for deletion
elif _area.is_in_group("hit_flash")
vida -= 9
vida = clamp(vida, 0, max_health) # OPT - Doesn't hurt to add
elif _area.is_in_group("planta_area"):
$lil.play("attack")
else: # OPT
return # OPT - Replace with any possible fallback animation?
This way, it will always it will check for death first. Since death is an absolute condition where the entity should always die if health is at zero. We can ensure this isn’t the case first and then proceed to the other conditions.
Because it is encased in a single if/else statement, it will execute one codeblock and should improve the reliability. Now, I added some additional stuff that I added the “OPT”(optional) comment to. Feel free to ignore them(especially the else and return part on the end)
A little note also. You have the variable health but you don’t have a max_health. It’s best to have a max_health constant and current_health defined. If an enemy/player can heal, have conditions(armor or buffs) that increase their health or for UI purposes like health bars and such. It also doesn’t hurt to use clamp() like I did which is used set a minimum and maximum.
Alright, well again. Without more info, there’s not much I can go on. Did you try the debugging steps? Add a breakpoint in the _on_area_2d_area_entered() function and use the “Step Over(F10)”. Note that the red circle to add a breakpoint doesn’t show until you mouseover it.
This will pause the game in the state it is when trying to execute the code of the breakpoint. It allows you to see what code the game executes and any variables + data pertinent in the debugger. If it doesn’t reach the desired code block. Then you have to make changes accordingly.
Additionally, is the signal connected properly? You can check this manually but you can also add in the _ready() method this:
if area_entered.is_connected(_on_area_2d_area_entered):
print("Signal is connected")
else:
printerr("Signal is NOT connected")
Otherwise, it’s most likely an issue where you have another play() call elsewhere that overrides the intended one.
Yes and no, this is already pretty simple but you can go about it a little differently using another signal to achieve the same thing. Instead of using await, connect the animation_finished signal and check that the animation was the death animation:
func _on_animation_finished():
if $lil.get_animation() == "ded":
queue_free()
func _on_area_2d_area_entered(area): # " _area" is not necessary anymore
if vida <= 0:
$lil.play("ded")
elif area.is_in_group("hit_flash") # Remove _
vida -= 9
if vida <= 0: # Added check if hit results with death
$lil.play("ded")
elif area.is_in_group("planta_area"): # Remove _
$lil.play("attack")
I haven’t used animation_finished and checked the animation in a while but from my memory, this can be a bit unreliable at times but I’m not sure. Try it and see if it works. Also, I simplified it to the bare minimum so it’s easier to test. The debugging process is often about stripping back features/code, seeing what works and what doesn’t. Also removed the underscore from area. Godot warned you because it wasn’t used in the function but you are so you can remove it again.
Additionally. I realized I forgot you need add a check to see if the enemy dies as a result of the attack hit so I added that too.
There are other things you can do like create your own signals and collision layers which isn’t complicated or hard to learn, but get the existing code to work before adding more.
Try introducing a boolean variable, like is_alive, to track if the enemy is alive. This will prevent it from playing the death animation while still in the attack state. Additionally, ensure that the death logic is executed only when the enemy’s health reaches zero. This should resolve the flickering issue. Studying International Relations, I had an essay on global conflict that I was struggling to finish. I used canadianwritings.com for help, and I’m really happy with the result. The writer delivered a well-structured and insightful paper that met all the requirements. It was delivered on time, and I got positive feedback from my professor. I’ll definitely use their services again.