Godot Version
4.6 stable
Question
How can I call keyframes from AnimationPlayer in script ?
I keep looking in documentation but not seeing word how to do a such thing .
I found markers and sections but this be extra work.
Use case : make sprite for each keyframe from current animation.
The track where is keyframes : Armature/Skeleton3D
So far I got this from docs :
However no word about keyframe or frame on track and what is track_idx and key_idx parameters ?
What exact information do you need to extract?
Animation::track_get_key_time() should get you the keyframe time. idx things are indexes of a track and a key. So if you want to consecutively position the animation player to keyframes, iterate from zero to Animation::track_get_key_count() get time of that keyframe and use AnimationPlayer::seek() to set the animation position.
1 Like
At a guess that would be track_get_key_value and loop through each key with the number from track_get_key_count.
Or is that too obvious 
1 Like
Good logic ,
I’ll try make it to code tomorrow
Tried a multiple things with this SpriteSheet generator , this seem to work for now as the code .
But one thing I noticed if I don’t use play and pause animation_player it gets confused and reacted only when I scrolled in script window, and also only used current_animation .
Is there some reason why is this working this way ?
small demo
@tool
extends SubViewport
@export_tool_button("Generate Sprite")
var generate_sprite = func():
var animation_player = $Barbarian/AnimationPlayer
var format = get_texture().get_image().get_format()
var animation_list = animation_player.get_animation_list()
for current_animation_number in animation_list.size():
var anim_name = animation_list[current_animation_number]
var anim = animation_player.get_animation(anim_name)
var track_idx = 0
var anim_frame_count = anim.track_get_key_count(track_idx)
var columns: int = 8 if anim_frame_count > 8 else anim_frame_count
var rows: int = anim_frame_count / columns
var name_of_spritesheet = "res://spritesheets/" + str(anim_name.replace('/','')) + ".png"
print("Animation: ", anim_name)
print("Frame count: ", anim_frame_count)
print("Animations count: ", animation_list.size())
var result = Image.create_empty(size.x * columns, size.y * rows, false, format)
var frame_index = 0
animation_player.play(anim_name)
animation_player.pause()
for r in rows:
for c in columns:
var key_time = anim.track_get_key_time(track_idx, frame_index)
animation_player.seek(key_time, true)
await get_tree().process_frame
await RenderingServer.frame_post_draw
var image = get_texture().get_image()
result.blit_rect(image, Rect2i(0, 0, size.x, size.y), Vector2i(size.x * c, size.y * r))
frame_index += 1
result.save_png(name_of_spritesheet)
print("completed one spritesheet"+ str(anim_name.replace('/','')))
with those two added lines
animation_player.play(anim_name)
animation_player.pause()
is there way I should organise animation_library and sprite2d texture switch of assets to make it seamless ? - end goal is make ready character2d with AnimationPlayer and loaded Sprite2D with change for current animation .
get_animation_list() doesn’t get you list of animations. Check the reference. To get all animation you need to query animationplayer’s animation library.
1 Like