"hurt" animation not playing

Godot Version

v4.1.2

Question

Hey there, I’m trying to play a “hurt” animation when my player gets hurt, so the idea is that when _on_deteccion_body_entered(body) an animation I’ve already set plays, but it just won’t… I’m sharing the code I have so far; thanks everyone!!

class_name Jugador
extends CharacterBody2D

var vida = 100 :
	set(valor):
		vida = valor
		$"Camera2D/CanvasLayer-life/HBoxContainer/HPProgressBar".value = vida
		if vida <= 0:
			morir()
		
var speed := 400
var Bala = preload("res://Escenas/bala.tscn")

func _input(event):
	if Input.is_action_pressed("disparar") and event is InputEventMouseButton:
		var bala = Bala.instantiate()
		bala.direccion = (get_global_mouse_position() - global_position).normalized()
		bala.global_position = global_position
		get_parent().add_child(bala)

func _physics_process(_delta):
	var movimientoJugador = Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
	
	if movimientoJugador.length_squared() > 0:
		# Player is moving, determine which animation to play
		if movimientoJugador.x < 0:
			if movimientoJugador.y < 0:
				$Sprite2D.play("moving_leftup")
			else:
				$Sprite2D.play("moving_left")
		elif movimientoJugador.x > 0:
			if movimientoJugador.y < 0:
				$Sprite2D.play("moving_rightup")
			else:
				$Sprite2D.play("moving_right")
		elif movimientoJugador.y < 0:
			# Moving up
			$Sprite2D.play("moving_up")
		elif movimientoJugador.y > 0:
			# Moving down
			$Sprite2D.play("idle")
	else:
		# Player is not moving, play idle animation
		$Sprite2D.play("idle")
	
	velocity = movimientoJugador.normalized() * speed
	move_and_slide()
	

var flagBool = false

func _on_deteccion_body_entered(body):
	if body.is_in_group("Enemigos") and !flagBool:
		flagBool = true
		vida-=body.damage
		$Deteccion/CollisionShape2D.set_deferred("disabled", true)
		$Deteccion/InmunidadTimer.start()
		

func morir():
	get_tree().reload_current_scene()


func _on_inmunidad_timer_timeout():
	flagBool = false
	$Deteccion/CollisionShape2D.set_deferred("disabled", false)
	

You need to write the code that plays the animation, something like $AnimationPlayer.play(“hurt”). The word “hurt” doesn’t appear in your code.

2 Likes

got it. thanks @ratrogue !
so what I did was this:

func _on_deteccion_body_entered(body):
	if body.is_in_group("Enemigos") and !flagBool:
		flagBool = true
		vida-=body.damage
		$Deteccion/CollisionShape2D.set_deferred("disabled", true)
		$Deteccion/InmunidadTimer.start()
        $Sprite2D.play("hurt")

but still doesn’t work, I’ve defined the animation in the Sprite2D node already, named “hurt”

1 Like

your hurt animation might be play for a delta/frame but then it immediately play other animation
make an argument so that when the hurt animation is playing it doesn’t trigger other animation

3 Likes

pham is right. You could use the animation_finished signal for waiting until the hurt animation finished.

1 Like

hey there! thanks for your answers @pham150603 & @ratrogue ; I’m a beginner so I was going in circles with this one, and found a solution; what I did was, I created a variable:

var currentAnimation = ""

And then modified the code for player movement and animation like this:

func _physics_process(_delta):
	
	var movimientoJugador = Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
	
	if movimientoJugador.length_squared() > 0:
		# Player is moving, determine which animation to play
		if movimientoJugador.x < 0:
			if movimientoJugador.y < 0:
				currentAnimation = "moving_leftup"
			else:
				currentAnimation = "moving_left"
		elif movimientoJugador.x > 0:
			if movimientoJugador.y < 0:
				currentAnimation = "moving_rightup"
			else:
				currentAnimation = "moving_right"
		elif movimientoJugador.y < 0:
			# Moving up
			currentAnimation = "moving_up"
		elif movimientoJugador.y > 0:
			# Moving down
			currentAnimation = "idle"
	else:
		# Player is not moving, play idle animation
		if currentAnimation != "hurt":
			currentAnimation = "idle"
	
	$Sprite2D.play(currentAnimation)

and the damage & hurt code, like this:

func _on_deteccion_body_entered(body):
	if body.is_in_group("Enemigos") and !flagBool:
		flagBool = true
		vida-=body.damage
		$Deteccion/CollisionShape2D.set_deferred("disabled", true)
		$Deteccion/InmunidadTimer.start()
		$Sprite2D.play("hurt")
		
		currentAnimation = "hurt"
		$Sprite2D.play(currentAnimation)

AND THAT DID THE TRICK!!!

thanks for your help!

TBH this doesn’t look quite right. Your hurt animation will stop instantly if you move, and if you don’t move, it will play indefinitely. But if it works for what you want to achieve, then it’s okay I guess.

By the way, you can remove the two lines with “$Sprite2D.play” in your
_on_deteccion_body_entered method.

1 Like

yes, you’re right, the “hurt” animation stops once I start moving… trying to tackle that as well.
but I just couldn’t achieve it the other way.

thnks!

if you using an animated sprite you can flag the loop by using the animation finish

1 Like

Well, with your currentAnimation variable you could do the following:

Add the following right after func _physics_process(_delta)::

	if currentAnimation == "hurt":
		$Sprite2D.play("hurt") # only necessary if you don't call $Sprite2D.play() in _on_deteccion...
		return

And you need a function which is connected to the animation_finished signal of your $Sprite2D:

func _on_animation_finished() -> void:
	if current_animation == "hurt":
		current_animation = ""
1 Like