AnimationTree plays the first frame of my idle animation before traveling to the next one

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

I am using an animation tree to change my game’s character’s animation. I am facing an issue when trying to play random idle animations.
The idea is to have a default idle animation on loop (“Walk_Idle” in the image below) and a random timer that makes the animation tree travel to one of the idle animations at random (“Walk_Idle_Breathe_In”, “Walk_Idle_Kiss”, or “Spin”). Then, once that animation finishes, it travels back to the default idle animation.

Every animation is made so that their start matches the end of the default idle animation, so the transition has its switch mode set to AtEnd.

The problem is that when I switch from “Walk_Idle” to the others, the first frame of “Walk_Idle” appears before the change happens.
An example would be that when going from “Walk_Idle” to “Walk_Idle_Breathe_In”, instead of doing:
“Walk_Idle” > “Walk_Idle_Breathe_In” > “Walk_Idle”
it does
“Walk_Idle” > first frame of “Walk_Idle” > “Walk_Idle_Breathe_In” > “Walk_Idle”

It doesn’t happen every single time, or at least I don’t notice it every single time, but it’s like 80% of the times.

This is my animation tree:
An image of my animation tree

The code I’m using:

onready var animationPlayer = $AnimationPlayer
onready var animationTree = $AnimationTree
onready var animationState = animationTree.get("parameters/playback")
onready var idleTimer = $IdleTimer

.

func _ready():
animationTree.active = true
randomize()

.

func walk_idle_state(delta):

velocity = velocity.move_toward(Vector2.ZERO, FRICTION * delta)
velocity = move_and_slide(velocity)

if animationState.get_current_node() != "Walk_Idle" && animationState.get_current_node() != "Walk_Idle_Breathe_In" && animationState.get_current_node() != "Spin" && animationState.get_current_node() != "Walk_Idle_Kiss":
	animationState.travel("Walk_Idle")
	start_idle_timer()
elif idleTimer.time_left == 0 && animationState.get_current_node() == "Walk_Idle":
	if first_idle_animation:
		var next_animation = pick_random_animation(["Walk_Idle_Breathe_In"])
		animationState.travel(next_animation)

	else:
		var next_animation = pick_random_animation(["Walk_Idle_Breathe_In", "Walk_Idle_Breathe_In", "Walk_Idle_Breathe_In", "Spin", "Walk_Idle_Kiss"])

		animationState.travel(next_animation)

var input_vector = get_input_vector()

if input_vector != Vector2.ZERO:
	first_idle_animation = true
	state = WALK


if Input.is_action_just_pressed("toggle_sneak"):
	first_idle_animation = true
	sneaking = true
	state = SNEAK
	
if Input.is_action_just_pressed("talk") && !talklist.empty():
	previous_state = WALK
	state = DIALOGUE

.

func start_idle_timer():
if first_idle_animation:
	idleTimer.start(0.6)
else:
	idleTimer.start(rand_range(1.0, 4.0))

.

func pick_random_animation(animation_list):
animation_list.shuffle()
return animation_list.pop_front()

.

func idle_animation_finished():

if animationState.get_current_node() == "Walk_Idle_Kiss":
	reset_time = 0.963
first_idle_animation = false
print(reset_time)
animationState.travel("Walk_Idle")
# WHY IS THIS BEING CALLED TWICE WHAT THE FUCK

.

func reset_idle_animation_time():
if reset_time != 0:
	animationTree.advance(reset_time)
	reset_time = 0

In the animationPlayer, there are a few Call Method Tracks:

The reset_idle_animation_time() function is called at the start of the “Walk_Idle” animation as a way to make is “resume” at a spot that fits the end of the other idle animations.

The start_idle_timer() and idle_animation_finished() functions are both called at the end of the idle animations, to return to “Walk_Idle”.

I made sure none of the animation player animations were on autoplay

I’m sorry if this is not very readable, it’s my first time posting on here, so I might have messed up the formatting

I also have this problem, but I use “Animation” blocks instead of “StateMachine”. Did you find a solution?

Here’s my post on Reddit

el_pablo | 2022-05-06 20:29

The only way I found to fix it was to make animations in a way that the first frame of the idle animation was the same as the first frame of the animation it switches to.
The problem is still there, but it’s not as visible since the “additional” frame is the same as the one that follows. It might not be possible based on your animations though

dragonixor | 2022-05-08 06:22