AnimationPlayer out of bounds error, texture update mode warning and flickering

Godot Version

4.2.1 Stable

Question

Hey.
I’m using the AnimationPlayer node for some 2d sprite animations and some stuff isn’t going how I was expecting.

Firstly, the debugger outputs the following warning and error messages

W 0:00:00:0464   _update_caches: AnimationMixer: 'idle', Value Track: 'Sprite2D:texture' uses a non-numeric type as key value with UpdateMode.UPDATE_CONTINUOUS. This will not be blended correctly, so it is forced to UpdateMode.UPDATE_DISCRETE.
  <C++ Source>   scene/animation/animation_mixer.cpp:879 @ _update_caches()
E 0:00:02:0920   set_frame: Index p_frame = 5 is out of bounds (vframes * hframes = 3).
  <C++ Source>   scene/2d/sprite_2d.cpp:235 @ set_frame()

The warning only happens once at the start and I think occurs because I change the sprite’s texture at the beginning of the animations but I thought that changing Update Mode to discreet would make it go away but it didnt.

The errors happen every time I land from a jump to a run. So, I have a jump animation with 3 frames, an idle with 10 frames and a run animation with 8 frames. The textures are split one texture per animation. The run animation has frame number 5 as its starting frame because it looks better as a transition from the idle frame, which I think somehow causes the errors. It happens every time I land from a jump which transitions from ‘jump’ to ‘run’.

Secondly there is also some flickering when transitioning between those two animations (that I’ve noticed). I understand that AnimationPlayer.advance(0) can ‘fix’ it but it feels hacky and I was wondering if I am making some kind of mistake.


Here’s the relevant code (ap is the instance of the AnimationPlayer):

func update_animation():
  # swap facing towards movement direction
  if h_dir != 0:
    sprite.flip_h = h_dir == -1
  
  if is_on_floor():
    if h_dir:
      ap.play('run')
    else:
      ap.play("idle")
  else:
    ap.play('jump')
    if abs(velocity.y) < 100:
      ap.seek(0.1) # mid jump frame
    elif velocity.y > 0:
      ap.seek(0.2) # jump descend frame
    else:
      ap.seek(0) # jump ascend frame
  
  # adding ap.advance(0) here fixes the flickering, but not the errors
  
  print(sprite.frame, ' | ', sprite.texture.resource_path, ' | ', ap.current_animation)

The print of the final line has the following output for the relevant frames which is what causes the flickering:

2 | res://assets/textures/charTemplate/Player Jump/player jump 48x48.png | jump
2 | res://assets/textures/charTemplate/Player Jump/player jump 48x48.png | run
2 | res://assets/textures/charTemplate/Player Run/player run 48x48.png | run
5 | res://assets/textures/charTemplate/Player Run/player run 48x48.png | run

Which seems weird to me.

First frame: We’re still jumping so it’s as expected.

Second frame: AnimationPlayer current animation has been updated but the sprite hasn’t which makes sense since it says in the docs that the animation gets update the next time the AnimationPlayer gets processed.

Third frame: Weird. The sprite texture has changed which means the animation has started yet the frame hasn’t changed, even though when I defined the animation the texture change and the frame change happen at the same time at the start of the animation.

Fourth frame: Finally all values are set correctly.

Also from this print output we can see that it seems at no point are we trying to set an out of bounts frame to a sprite that doesn’t have it.

As I said before if I add ap.advance(0) after all animations are set in the code the output is the following:

2 | res://assets/textures/charTemplate/Player Jump/player jump 48x48.png | jump
5 | res://assets/textures/charTemplate/Player Run/player run 48x48.png | run

Flickering is gone and it looks right, however the errors and warning don’t go away.


Misc questions/notes about 2d animations:

  • Are the textures cached or is constantly swapping them expensive and wasteful?
  • If they’re not cached, is there some way to load them all when the player node starts and then use them with the animation player?
  • Let me know if you don’t like the way I used the AnimationPlayer and please share any tutorials about it if you have any you like. I get the feeling I’m missing stuff about it but I’m not sure exactly how it’s designed to be used. The ‘seek’ calls definitely feel wrong.
  • The goal of doing this is to figure out the best way to do animations for 2d sprite characters. If you have any suggestions about this please share your thoughts.