Need help with implementing a "secondary_idle" animation

Godot Version

4

Question

Hello,
I am trying to introduce a second idle animation that plays after a set amount of time while the first idle animation plays. I have tried using a timer before asking if the first idle animation is playing to play the second idle animation.

The timer seems to work fine, but the second idle animation skips frames and gets stuck as the default animation, even while the character is moving (a problem with the if statement?)
The AnimatedSprite2D node does not seem to have any other methods for checking whether a specific animation is playing, only that if an animation is playing.
Not sure if the AnimationPlayer node can be linked to this either.
Is there any way to get around this problem without using an AnimationTree node?

Quite new to Godot, so any help is appreciated. Thanks.
Using a DevWorm tutorial.

Before setting new animation (line 124) you should check if it still playing idle animation (you’re checking is playing any animation, it means that it could be played even if player is moving or jumping or …)

To check which animation is playing at the moment just use it:

if animation_player.animation == “idle”:

Then, I want to ask you - from where you’re calling this function? If you’re calling it from _process or _physics_process funcs - that’s why your animation is stuck, cause you’re repeating it every frame. Like an example:
You’re saying every second start to play animation, again, again, again and again - that’s why it can’t continue to play it (cause it starts every frame)

To avoid it, before calling animated_sprite.play() - you should check which animation is playing, here’s an example to your 120 line:

> if !velocity:
>     if animated_sprite.animation != "idle":
          animated_sprite.animation.play("idle")

I hope it makes sense to you :grin:

1 Like

Thanks!
This was really helpful. The function is being called in _physics_process, and the animation stopped stuttering after I checked which animation was playing.
Can .animation be used for an AnimatedSprite2D node as well? I have tried using:

image

image

but this causes the first idle animation to play a few times (for 5 seconds) before speeding up and slowing down again, rather than stopping or buffering (the first idle animation is on loop). Should a signal or separate function be used instead?

Well, if I understand you right, your question is - has AnimatedSprite2D .animation or something similar to it? - answer: yes, I want to guide you how to find this kind of “invisible” properties:


Look, every properties in insperctor could be called from code, if you just hover any property with your mouse - you can see description about this property + how to call it from script. In this photo we can see that AnimatedSprite2D has property Animation which could be called in code by “animation” tag and you’ll get “The current animation …”

One more information:
image
Every node has an image-button called DOC:
image

If you just press it - you’ll see all Properties, Methods, Signals, Description:


Like an example, there’s property called “animation”, which returns StringName parameter and you can set it and even get (set_animation, get_animation)

1 Like

It would be much better to make counter or signal to play second animation (and check if second anim is playing - not to play first anim). I believe, that method with timer isn’t good, cause it’s not have logic “start after finishing it”, instead it has logic “when to start” - it means that doesn’t matter finished animation before or not - just play it when times come

1 Like

This makes a lot more sense! Thank you. The DOC function is very useful.

I have placed the - check if secondary_idle animation is not playing - and this seems to work much better. All animations play respectively, and there is no buffering/speeding up/slowing down.

However, the secondary animation itself does not play when the timer is up, or even if there is no timer present. I printed the current animation playing, and all animations play at the appropriate time. Only the secondary animation does not play, although the current animation being printed shows that it is (with or without the timer).

The secondary idle also entirely replaces the first idle after any other movement animation is completed, rather than returning to the first idle animation.

Any idea why this may be? Sorry I’m still very much a novice to all this.

If I were to use a signal instead of the timer, would I have to connect a new animation_finished() signal to a function (that plays the secondary idle) and call that function within this movement function?
I believe I would need to specify which animation I want a signal emitted for when it is finished.

Once again, thank you so much for all the help.

1 Like

It’s not playing the first idle animation because you’re setting every frame it to second idle animation in line 128
Like: you’re resetting every frame to Idle animation on line 125 and then on line 127 checking if it’s not second idle animation - play second idle animation

Every frame you’re rechanging it now)

If you understood everything above, then I want to advice you to add idle_anim_counter variable. Which should count every time when idle animation is finished (and reset this counter only if animation different from idle animation)
On line 127 (where you’re checking if it’s not second idle animation) just write this:

if animated_sprite.animation != “secondary_idle” and idle_anim_counter % 5 == 0:

It means that every time when idle animation have played N times (here I’ve put 5 but it doesn’t matter) secondary idle will be played

Also, look at your line where you’re setting idle animation, you’re not checking if it’s already playing

If you misunderstood something, don’t feel dumb, just say it, I’ll explain it more detailed later, cause I’m writing it now on my mobile phone :sweat_smile:

1 Like

Is this how I use the counter? (the counter var is set to integer)
It works perfectly, and the animation always returns to the first idle animation (after any other animation like run/jump),
but the secondary animation either does not get enough time to play out fully, or does not play at all.
It does play at the correct time as expected with the counter, however.

Just for my own knowledge, if I understand correctly, my earlier mistake was that every frame was being set to the first idle animation → immediately checking if it is not the secondary idle animation → play the secondary idle animation. Because this occurred every frame, the player was stuck on secondary idle animation?

Thanks :sweat_smile:

Yes, you understood me right)

Second animation can’t be played fully cause you’re not checking if it’s playing second idle animation before 125 line

Look:
You’re checking if Idle animation has played 10 times and you’re not already playing second animation → play it
However, you’re not checking if you’re playing second animation right now before playing first animation

I know, it feels like something annoying (it is) but it has logic. When you’re starting to play your second animation → you immediately playing first idle animation, cause you’re not checking if second animation is playing. I hope it was explained OK)

You should start to play idle animation only when second animation has been played, if you can’t do it - I’ll help you)

1 Like

So for each frame, the first idle animation is played regardless of whether the second idle animation is played or not, so the second idle animation is not given enough time to play despite the counter triggering it?
From what I understand, by checking if the secondary idle is playing, we remove the first idle animation overlapping it and resetting the counter.

Anyhow, this worked! The first idle animation transitions smoothly into the second, and there is no stuttering or animations getting stuck.

Using a counter like so is a useful alternative to a timer or signal. I have certainly learnt a lot.
Thanks so much for your help, this is exactly what I wanted!

1 Like

Exactly, I hope you fully understand everything that I tried to explain)
This is not the best solution but works fine)
And the last thing I want to check - is after second idle animation finished first idle starts working?

1 Like

The second idle animation is kind of a ‘sitting-down’ animation, and it stays static until the player moves again. After that, the first idle animation starts working again as normal, if that is what you mean. Technically, this animation is not looped, so no - after the animation is completed the player stays seated on the last frame, which works well for me.

But if you’re talking about an animation like a weapon-inspect or something that returns to the original idle, I’m not sure - I don’t think it would return to the first idle unless the player moves (is no longer under the - if !velocity - statement).

Is there a way to do this?

1 Like

Oh, I understood you, it’s cool. Cause in your code I see that after second anim it won’t play first idle anim until you start to move/jump

And I’ve noticed that you’re increasing your anim_counter each frame (it’s not good, because on each device will be different frame rate per second)

You should increase it only after idle_anim finished playing, like this:

If you want to return to idle animation after pickup weapon or something like this - just set your idle_counter to zero

Also, instead of:

if velocity:
   ..
if !velocity:
  ..

You can just write:

if velocity:
   ..
else:
   ..
1 Like

This makes a lot more sense to do.
But since the idle animation is a loop of a short animation, it seems the secondary idle animation plays after a single play of the first idle animation, instead of waiting N number of times for the first animation to finish playing.
Is this because of the animation_finished signal?

Yeah you are right ‘if’ and ‘else’ is simpler than ‘velocity’ and ‘!velocity’ :sweat_smile:

Oops… if animation is a loop - then it won’t emit animation_finished signal, instead of loop I’d recommend you now to repeat it from your code

func on_animation_finished(anim_name: String)
if anim_name == “idle”:
animation_sprite.play(“idle”)
idle_anim_counter += 1
else:
idle_anim_counter = 0

I have disabled the loop on the animation itself, but it seems the same problem still occurs.
So it plays once, during the movement func, and then the signal picks up that it is an idle animation and repeats it using the on_animation_finished func.
Is there something I need to change within the movement function as well?

If I understood you right - second animation isn’t playing
It will be played after 600 times idle animation have been played as I see in your script)
Try something lower)

Also, lines 19 and 21 (I guess not these lines, I can’t see exact lines) - you don’t have to check double times if it’s not second animation, you can delete it on line 21 if you want (not condition after AND)

If the problem will still occur after it, I’ll check it on my PC later

No it seems the problem is similar as when I first introduced the signal func:

“it seems the secondary idle animation plays after a single play of the first idle animation,”

but this time, according to the printed script, the first idle animation never plays after a movement.
image

My bad, I didn’t take a proper screenshot.


Well, after some tests I’ve noticed that I’ve made a mistake - I was testing with AnimationPlayer instead of AnimatedSprite

AnimatedSprite a bit different from animation player, for example - you can’t play animation if it’s already playing
But it’s easy to fix - just set Frame to 0 and then Play (like my 41-42 lines)

Also, I’ve noticed that if your run/jump animation is a loop, you should do it as my lines from 44 on first photo. However, if your anim isn’t a loop, then just do this:
image

To be shorter: for loop animations - do like 44-47 lines, for unloop animations - do nothing (just add 49-50 lines and it would be cool)

Everything works fine, I’ve finally tested it and decided to use condition like in my 29 line, instead of idle_anim_counter % 5 == 0, cause it’s a bit harder to understand and idle_anim_counter mustn’t be zero in that scenario

If you didn’t understand something - reply me)

1 Like