I have a scene that looks like this:

[gd_scene load_steps=6 format=2]

[ext_resource path="res://source/combat/CombatEntity.tscn" type="PackedScene" id=1]
[ext_resource path="res://source/combat/playable_combat_character.gd" type="Script" id=2]
[ext_resource path="res://assets/sprites/player_character_placeholder_1.png" type="Texture" id=3]
[ext_resource path="res://assets/sprites/player_character_placeholder_2.png" type="Texture" id=4]

[sub_resource type="SpriteFrames" id=1]
animations = [ {
"frames": [ ExtResource( 3 ), ExtResource( 4 ) ],
"loop": true,
"name": "default",
"speed": 5.0
} ]

[node name="PlayableCombatCharacter" instance=ExtResource( 1 )]
script = ExtResource( 2 )

[node name="AnimatedSprite" parent="." index="0"]
position = Vector2( 16, 16 )
frames = SubResource( 1 )
flip_h = true

I'm trying to recreate the animated sprite portion of this programmatically in GDScript.

I've looked at the documentation for the AnimatedSprite and SpriteFrames classes, but the methods and properties in the documentation don't give me a clear picture as to how to setup the objects appropriately.

After some trial-and-error and exploring the objects at runtime, this is what I eventually came up:

class_name PlayableCombatCharacter
extends CombatEntity

func _ready() -> void:
	var animated_sprite: AnimatedSprite = AnimatedSprite.new()
	
	animated_sprite.position = Vector2(100,100)
	animated_sprite.flip_h = true

	var image1 = load("res://assets/sprites/player_character_placeholder_1.png")
	var image2 = load("res://assets/sprites/player_character_placeholder_2.png")

	var animation = {}
	animation.name = "default"
	animation.speed = 5.0
	animation.loop = true
	animation.frames = [image1, image2]
	animated_sprite.frames = SpriteFrames.new()
	animated_sprite.frames.animations = []
	animated_sprite.frames.animations.append(animation)
	
	add_child(animated_sprite)

The problem is that the array stays empty:

I assume the reason is:

Compatibility property, always equals to an empty array.

The above is from the documentation for the SpriteFrames class.

What am I doing wrong? What is the correct way to set this up?

Once I found out the loaded images are StreamTextures, I was able to make more sense of the available methods on SpriteFrames.

Here is the updated code, which is now working:

class_name PlayableCombatCharacter
extends CombatEntity

func _ready() -> void:
	var animated_sprite: AnimatedSprite = AnimatedSprite.new()
	
	animated_sprite.position = Vector2(100,100)
    animated_sprite.flip_h = true

	var image1: StreamTexture = load("res://assets/sprites/player_character_placeholder_1.png")
	var image2: StreamTexture = load("res://assets/sprites/player_character_placeholder_2.png")
	
	animated_sprite.frames = SpriteFrames.new()
	animated_sprite.frames.add_animation("default")
	animated_sprite.frames.add_frame("default", image1, 0)
	animated_sprite.frames.add_frame("default", image2, 1)
	animated_sprite.frames.set_animation_loop("default", true)
	animated_sprite.frames.set_animation_speed("default", 5.0)
	
	add_child(animated_sprite)
2 years later