How do I detect an animation ending using Animation Tree?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By mars

Hi,
I am attempting to write a movement system in 2D for an isometric game using animation_tree.

The problem I am encountering is the player can move during the attack animation, whereas I would like the player to stay still.

I know I need to await (yield) until the animation is finished, however, if I use await $AnimationPlayer.animation_finished it yields forever.

What should I be using instead?

extends CharacterBody2D
@onready var animation_tree = get_node("AnimationTree")
@onready var animation_mode = animation_tree.get("parameters/playback")

var max_speed = 400
var speed = 0
var acceleration = 1200
var move_direction = Vector2(0,0)

var moving = false
var attacking = false

# Called when the node enters the scene tree for the first time.
func _ready():
	pass # Replace with function body.
	
func _physics_process(delta):
	MovementLoop(delta)

# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
	pass
	
func _unhandled_input(event):
	if event.is_action_pressed('CLICK'):
		moving = false
		attacking = true
		print(position.direction_to(get_global_mouse_position()))
		animation_tree.set('parameters/Melee/blend_position', position.direction_to(get_global_mouse_position()).normalized())
		animation_tree.set('parameters/Idle/blend_position', position.direction_to(get_global_mouse_position()).normalized())
		Attack()
	
func MovementLoop(delta):
	if attacking == true:
		return
		
	move_direction.x = int(Input.is_action_pressed("WALK_RIGHT")) - int(Input.is_action_pressed("WALK_LEFT"))
	move_direction.y = (int(Input.is_action_pressed("WALK_DOWN")) - int(Input.is_action_pressed("WALK_UP"))) / float(2)
	
	if move_direction == Vector2(0,0):
		animation_mode.travel("Idle")
		speed = 0
	else:
		speed += acceleration * delta
		if speed > max_speed:
			speed = max_speed
		var movement = move_direction.normalized() * speed
		velocity = movement
		animation_tree.set('parameters/Walk/blend_position', movement.normalized())

		animation_tree.set('parameters/Idle/blend_position', movement.normalized())
		animation_mode.travel("Walk")
		move_and_slide()
	
func Attack():
		animation_mode.travel("Melee")
		#await here
		attacking = false

I also encountered this problem in Godot 3.4. I am very disapointed to see that it is still there in newer version. AnimationTree does not have its own “animationfinished” signal, and it prevents AnimationPlayer from signalling.

I really hope someone comes up and says it is fixed. Until then, this is how I assesed this situation :
I had to get the animation lenght from AnimationPlayer and yield(get_tree().create_timer(animationlenght),"timeout")
So You can do this with new wait() function. In older version this was not a best sollution, because pause didn’t work with dynamic timers and pausing project let players cheat and hasten stagger effects :slight_smile:

Inces | 2022-04-12 19:35

Do you know if pause works with dynamic timers in 4.0?

mars | 2022-04-12 20:31

no, I won’t update until I finish my current project. But You can easily test it. Create one sprite, await (yield) 10 seconds, create another sprite. Run this code and try to pause for 10 seconds inbetween sprite creations. If it is broken as in Godot 3, second sprite will be created immadietely after unpausing, otherwise it should hold another 10 seconds.

Inces | 2022-04-14 14:52