Animation interrupted by another one

Godot Version

Godot 4.3

Question

Ask your question here! Try to give as many details as possible
Hi everyone,
i am making a 2d platformer; while playing an animation (“attack”) it run another animation (“idle”) without fully run the previous animation…Mmmm, i thougth a way so solve this probblem is defining come flag variable to indicate wn animation is already running…what do you think about ?

No need to define a flag. The animation can tell you when it’s finished.

There’s also a is_playing() function if you want to check right away if an animation is playing.

ok, considering I defined this to play the several animations:
var animation_player: AnimationPlayer
Could I check if no one animation is being played?? :no_mouth:

Yes, as @paintsimmon mentioned you can use is_playing:

if not animation_player.is_playing():
  # do-stuff

Or you use current_animation to get the currently playing animation (it’s "" when none is playing). Or you connect/await the animation_finished signal as @TokyoFunkScene suggested and start the next animation when the previous is finished.
Or you use queue to queue the next animation.

I suggest you take a look at the documentation, all properties, methods and signals are listed and explained there: AnimationPlayer — Godot Engine (stable) documentation in English

There you will probably find what fits your use-case best :).

use an AnimationTree.
you can use expressions to make things easier, they will read variables in one of your files, so you don’t have to get the AnimationTree to change values manually all the time.
here’s a tutorial on expressions while they update the docs:
https://godotforums.org/d/39521-this-is-how-to-use-animationtree-state-machine-transitions-with-expressions

do not use an AnimationPlayer on its own unless it’s for something very simple, and in that case an AnimatedSprite would be better.
explosions, single looped animations = AnimatedSprite
characters, enemies, a chest, a door = AnimationPlayer with AnimationTree

Your other question was about setting up collisions? and I told you to use a state machine?
well with an AnimationTree you could define in what order you want the animations to run, or if an animation must not transition at all, like a death animation.

idle -> hurt -> death
idle -> electricity -> death

you can also make them go back when a condition is met, like with walking:

idle -> walk
walk -> idle

an AnimationTree will also ensure that an animation finishes playing before going into the next one, and you can set it to smoothly transition, blending frames from one with the next.

2 Likes

Hello.

I write here to not duplicate posts.

My code works fine, eaven with “idle”, but when i “attack” its like split secound animation.
I dont know how to repair that.

func _process(delta):
	var move_vector: Vector2 = Input.get_vector("move_left", "move_right", "move_up", "move_down")
	velocity = move_vector * 15000 * delta

	if Input.is_action_just_pressed("attack"):
		$AnimatedSprite2D.play("attack")
	elif  velocity.x > 0:
		$AnimatedSprite2D.flip_h = false
		$AnimatedSprite2D.play("move")
	elif velocity.x < 0:
		$AnimatedSprite2D.flip_h = true
		$AnimatedSprite2D.play("move")
	else:
		$AnimatedSprite2D.play("idle")
	move_and_slide()

Put a print statement in each of your if/elif/else blocks to see what gets executed and when.

Looking at the code, Input.is_action_just_pressed() only checks for 1 frame of the specified input, so it’s probably only playing the attack animation for 1 frame, because it’s nested in a bunch of if/elif/else statements.

In other words, the condition of the attack button being pressed is only true for one frame, so the animation plays for one frame then the idle animation begins to play again.

You may have to rewrite the if conditions so they play properly, and maybe throw in an await() command (or use a Timer Node) to make sure the attack animation finishes.

And of course, here is the obligatory “Have you tried using a State Machine” question, it can help compartmentalize your animations as well as give you modular control over each individual action.

Everything make just in 0.0001sec.

attack start
attack stop
idle

@skyekun I try other options, other builds, and even separated “if” for “attack”, everything doesn’t works

func _process(delta):
var move_vector: Vector2 = Input.get_vector(“move_left”, “move_right”, “move_up”, “move_down”)velocity = move_vector * 15000 * delta

if Input.is_action_just_pressed("attack"):
	print("attack start") 
	$AnimatedSprite2D.play("attack")
	await $AnimatedSprite2D.animation_finished
	print("attack stop")
	
if velocity.x > 0 and $AnimatedSprite2D.animation_finished:
	$AnimatedSprite2D.flip_h = false
	$AnimatedSprite2D.play("move")
elif velocity.x < 0:
	$AnimatedSprite2D.flip_h = true
	$AnimatedSprite2D.play("move")
else:
	print("idle")
	$AnimatedSprite2D.play("idle")
move_and_slide()

You should make your own post so that you can mark the solution that helped you and help people who come after you. By extending a post by someone else, you cannot do this.

Put prints in all blocks, not just attack and idle. No awaits, they’ll just make your problem worse and code execution harder to mentally follow.

And yeah, make a new thread.