Animations with AnimationPlayer flickering when starting

Godot Version

Godot v4.5.stable.official.876b29033

Question

I’ve been using an AnimationPlayer node to add simple animations to certain game objects. These animations appear in the editor just fine, but when loaded into gameplay consistently draw incorrectly for a frame before their animation plays.

For example, a UI element is supposed to fade in smoothly with modulate and position when the player character enters a certain area, but this animation is preceded by a frame where it is at full opacity and in its default position, before snapping to (what seems to be) the next frame after what should’ve been the first frame of the animation.

This issue affects many other objects in the game, and suggested solutions to related problems online haven’t helped so far. This affects many different node types, although Node2D seems to break even more, for reasons I also cannot understand.

Any help or advice here would be appreciated.

Check the values in the RESET animation and modify/remove them accordingly.

My understanding is that RESET simply sets the states that AnimationPlayer uses back to a specified default state, and I understand that it will run this animation as the first thing that an animated scene does. What I don’t understand is why this bleeds into other animations.

If RESET has one setting saying position.y is 0, and “spawn” is played, setting position.y to -50 at 0.0 seconds, then it shouldn’t matter what RESET is set to at any time. Does 0.0 seconds not actually mean 0.0 seconds? Is there some sort of delay in animation playback?

Additionally, what does this mean if I actually have MULTIPLE animations that I may want something to start with? Say one animation makes position.x set to -10, and another makes it set to 10 when the sprite first appears. What is RESET supposed to be, if it guarantees one frame of bleed into either animation?

The RESET track will reset the values when saving the scene if AnimationMixer.reset_on_save is true (it’s true by default) so those are going to be the default values the scene will have when you instantiate the it. Playing an animation will happen after the scene is instantiated so there may be a frame where the node has the RESET values. More info:

Is that sort of the bottom line, then? Is there no way to make it so that RESET isn’t what is loaded, or to stop it from occasionally appearing for a frame before the next intended animation? I at least appreciate the effort made to explain this, I certainly feel less insane for noticing this happening.

The way that it appears, as well as its inconsistency, makes it seem like a bug, in which case I’m surprised that I haven’t seen anyone else note upon it before.

To make the problem clear, I am trying to make enemies appear with animations that use modulate to make their AnimatedSprite2D smoothy transition in with opacity. Some enemies of the same type will not need this transition however, and it would be nice to actually be able to see the sprites in the editor when adding them to environments. As a result, simply letting RESET default their opacity to 0 is not a practical solution here.

The issue seems to be related to the fact that the enemies’ visible is set to false before they are allowed to appear in gameplay, which I assume prevents animations from invisibly being loaded and playing out until it is set to true, at which point it seems to “crush” its RESET and spawning animations together. It doesn’t make a difference when the animation plays relative to the show() function.

If there is any possibility that there is SOME solution to this specific problem that doesn’t require some incredibly complicated workaround that I would have to replicate for god knows how many scenes across the entire project, I would appreciate hearing it.

Regardless, happy birthday mrcdk.

Could you post the code, scene structure, and animations?. This shouldn’t happen. The animation should play regardless of the node’s visibility.

You can see a video of the problem in action here: https://youtu.be/qfL8FFPDjis
After one wave of enemies is defeated, the next wave is set to spawn in with a spawn animation. The twist is that they appear without the animation for a frame, before beginning the animation as expected.

When examining the code for the specific Puffer enemy shown in the video, the code that makes it visible and the part that makes it play its animation are closely related.

for a start, it checks whether or not it is a “frontline” or “reinforcement” of the specific ambush, which determines whether or not it will be visible by default, as well as whether or not it bothers using the spawn animation. The individual in the video is of course a "reinforcement” type, whose code is as follows:

## (There are other elifs and ifs before this for the other types of enemy in an ambush)
elif spawn_type == "reinforcement" and Global.ambush_current == ambush and Global.ambush_wave == ambush_wave:
			visually_apparent = true
			$AnimationPlayer.play("spawn")
			$SpawnTimer.start()
			state = States.ACTIVE

## IF THE ENEMY IS VISIBLE
if visually_apparent:
	show()
    ## More code follows this that isn't important here.

By the end of this sequence, the enemy will begin playing its animation and begin being visible. It has never been instructed to play any animation before this. Also, for the record, I checked having the show() function play before the animation rather than setting visually_apparent to true in its stead, though it made no difference.

The Puffer’s node structure is simple, and displays as follows:

  • Puffer [CharacterBody2D]
    • Sprite [AnimatedSprite2D]
    • HealthBar [Instantiated Scene, Node2D]
    • CollisionBox [CollisionShape2D]
    • SpawnTimer [Timer]
    • AnimationPlayer [AnimationPlayer]

The relationship between AnimationPlayer and Sprite is what you’d expect.

Here’s the spawning animation. Needless to say, RESET just sets the Sprite to display at default position and modulate.

image

Hopefully somewhere along here I have said something that rings as an obvious rookie error. It’s worth stating that all nodes in the game that animate right out of them being visible like this have this same problem, and any that (like the score numbers that come off of defeated enemies) are only seemingly not broken because their RESET has been set to align with the beginning of their spawning animation. This is fine as a workaround for an object that only has one animation and incredibly simple behaviour, but strikes me as unwise for complex enemies.

You should make a minimal reproduction project and post it.

Okay, I though you were delaying the show() call which would be a bug but that’s not the case.

The RESET animation will reset the values and, as explained in the documentation, AnimationPlayer.play() will update the next time the AnimationPlayer is processed:

Note: The animation will be updated the next time the AnimationPlayer is processed. If other variables are updated at the same time this is called, they may be updated too early. To perform the update immediately, call advance(0).

You can use AnimationMixer.advance() or AnimationPlayer.seek() with 0 after AnimationPlayer.play() to force the values to the ones of the animation.

From what I can see so far, adding $AnimationPlayer.seek(0) after the play function has solved the problem. I appreciate it immensely. I will try to wrap my head around precisely what is going on here, and what went wrong before. Thank you!

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.