+3 votes

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 ("WalkIdle" in the image below) and a random timer that makes the animation tree travel to one of the idle animations at random ("WalkIdleBreatheIn", "WalkIdleKiss", 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 "WalkIdle" to the others, the first frame of "WalkIdle" appears before the change happens.
An example would be that when going from "WalkIdle" to "WalkIdleBreatheIn", instead of doing:
"WalkIdle" > "WalkIdleBreatheIn" > "WalkIdle"
it does
"Walk
Idle" > first frame of "WalkIdle" > "WalkIdleBreatheIn" > "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 resetidleanimationtime() function is called at the start of the "WalkIdle" animation as a way to make is "resume" at a spot that fits the end of the other idle animations.

The startidletimer() and idleanimationfinished() 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

Godot version Happened on 3.4.2, switching to 3.4.4 didn't fix it
in Engine by (15 points)

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

Here's my post on Reddit

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

Please log in or register to answer this question.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read Frequently asked questions and How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to [email protected] with your username.