How to add frames from a sprite-sheet in code?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Pomelo

I have an scene with an AnimatedSprite, and I want to change the textures of the SpriteFrames when instancing the scene. When you have individual textures for each frame this can be done with for example set_frame( "idle", 3, loaded_texture)

Question is, how can I achieve the same thing if I have a sprite-sheet? I would guess that I would need a method to obtain the individual textures from the sprite-sheet (similar to what can be done in the editor with the add frames from sprite-sheet button.

:bust_in_silhouette: Reply From: ominocutherium

This is what AtlasTexture is for: a texture resource which is an individual sprite cut-out from a larger sprite sheet (or atlas). After creating the AtlasTexture in code, assign its atlas property to the loaded sprite sheet, and its region property to the Rect2 with the coordinates of the upper left coordinate of the sprite in the spritesheet, along with the sprite size.

Here is a code example of an AnimatedSprite, SpriteFrames and one AtlasTexture for each frame, all created through code:

extends Node2D
func _ready() -> void:
    var anim_sprite := AnimatedSprite.new()
    	var sprite_frames := SpriteFrames.new()
    	sprite_frames.add_animation("idle")
    	sprite_frames.set_animation_loop("idle",true)
    	var texture_size := Vector2(64,64)
    	var sprite_size := Vector2(32,32)
    	var full_spritesheet : Texture = load("res://icon.png")
    	var num_columns : int = int(texture_size.x/sprite_size.x)
    	for x_coords in range(num_columns):
    		for y_coords in range(int(texture_size.y/sprite_size.y)):
    			var frame_tex := AtlasTexture.new()
    			frame_tex.atlas = full_spritesheet
    			frame_tex.region = Rect2(Vector2(x_coords,y_coords)*sprite_size,sprite_size)
    			sprite_frames.add_frame("idle",frame_tex,y_coords*num_columns+x_coords)
    	anim_sprite.frames = sprite_frames
    	add_child(anim_sprite)
    	anim_sprite.position = Vector2(32,32)
    	anim_sprite.play("idle")