AnimatedSprite2D and Sprite Animation

SpriteFrames, idle/walk, directional anims, flip_h, import filter, scale.

stablegodotanimation
On this page
Character idle facing the camera
Directional idle (facing down / toward camera).
Character on lobby floor
Same AnimatedSprite2D pipeline for player and guests; guests swap SpriteFrames from data.

Godot-side workflow (what we did)

  1. Import PNG frame sequences (clerk, student, per-guest sheets).
  2. Build a SpriteFrames resource (.tres) with animations: idle_*, walk_*.
  3. Assign on AnimatedSprite2D in 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 / walk names the code expects.
  • centered props on full-room canvases — sprites authored full-size need centered = false or 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).