AnimatedSprite2D and Sprite Animation
SpriteFrames, idle/walk, directional anims, flip_h, import filter, scale.
On this page
AnimatedSprite2D pipeline for player and guests; guests swap SpriteFrames from data.Godot-side workflow (what we did)
- Import PNG frame sequences (clerk, student, per-guest sheets).
- Build a
SpriteFramesresource (.tres) with animations:idle_*,walk_*. - Assign on
AnimatedSprite2Din the clerk scene, or swap at runtime for guests.
if guest_data.sprite_frames != null:
$AnimatedSprite2D.sprite_frames = guest_data.sprite_frames
$AnimatedSprite2D.scale = Vector2.ONE * guest_data.sprite_scale
Switching animations from code
Only call play when the animation name changes (avoids restarting every frame):
func _play_anim(kind: String) -> void:
var frames: SpriteFrames = $AnimatedSprite2D.sprite_frames
var directional := "%s_%s" % [kind, _facing]
var anim := directional if frames.has_animation(directional) else kind
if $AnimatedSprite2D.animation != StringName(anim):
$AnimatedSprite2D.play(anim)
Facing with flip_h
Side sheets may face left or right depending on the artist. Guest JSON carries side_faces_left; clerk uses a const. Flip when moving opposite the art’s native facing.
Texture filter
project.godot:
textures/canvas_textures/default_texture_filter=0 # nearest
Keeps pixel / crisp art from blurring when scaled.
Scale contract
Room backgrounds stay at scale 1.0 (1 pixel = 1 world unit). Characters use scene scale (~0.65) plus optional per-guest sprite_scale. Do not rescale room art to fix character size.
Common import mistakes
- Forgetting transparency (use PNG with alpha).
- Mixing filter modes (nearest vs linear) across sheets.
- Putting all frames in one animation without
idle/walknames the code expects. centeredprops on full-room canvases — sprites authored full-size needcentered = falseor they jump by half a room.
Guest motion sync
Guests pick walk vs idle from get_real_velocity().length() > 2.0 after move_and_slide, not from the input vector (they have none).