Sprite frames par code

Un cycle de marche de huit images peint dans des buffers Image au démarrage puis confié à un AnimatedSprite2D. La bande du bas est le SpriteFrames lui-même.

L'éditeur ci-dessus fait tourner ce projet. Changez une ligne et il se recharge.

Classes Godot utilisées

AnimatedSprite2DSpriteFramesImageTexture

Le code

scripts/main.gd
extends Node

const FRAME_SIZE: int = 24
const FRAME_COUNT: int = 8
const FPS: float = 10.0
const STRIP_Y: float = 570.0
const STRIP_STEP: float = 96.0

const SKIN: Color = Color('#8da5f3')
const LEG: Color = Color('#5f74b8')
const EYE: Color = Color('#12141a')

var sprite: AnimatedSprite2D
var highlight: ColorRect


func _ready() -> void:
	_add_background()
	_add_label('every frame is an Image painted pixel by pixel at startup', Vector2(40, 40))

	var frames: SpriteFrames = SpriteFrames.new()
	frames.set_animation_speed('default', FPS)
	frames.set_animation_loop('default', true)

	for i in FRAME_COUNT:
		frames.add_frame('default', _make_frame(i))

	sprite = AnimatedSprite2D.new()
	sprite.sprite_frames = frames
	sprite.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST
	sprite.scale = Vector2(11, 11)
	sprite.position = Vector2(640, 300)
	add_child(sprite)
	sprite.play()

	_add_strip(frames)

	print('the strip below is the SpriteFrames, the highlight is the frame on screen')


func _process(_delta: float) -> void:
	highlight.position.x = _strip_x(sprite.frame) - STRIP_STEP * 0.5


func _make_frame(index: int) -> ImageTexture:
	var image: Image = Image.create(FRAME_SIZE, FRAME_SIZE, false, Image.FORMAT_RGBA8)
	image.fill(Color(0, 0, 0, 0))

	var phase: float = TAU * index / FRAME_COUNT
	var bob: int = int(round(sin(phase) * 1.5))
	var swing: int = int(round(sin(phase) * 2.0))
	var body: Vector2 = Vector2(12, 11 + bob)

	_fill_rect(image, Vector2i(8 + swing, 17), Vector2i(3, 6), LEG)
	_fill_rect(image, Vector2i(14 - swing, 17), Vector2i(3, 6), LEG)

	for y in FRAME_SIZE:
		for x in FRAME_SIZE:
			if Vector2(x, y).distance_to(body) <= 7.2:
				image.set_pixel(x, y, SKIN)

	_fill_rect(image, Vector2i(9, 9 + bob), Vector2i(2, 2), EYE)
	_fill_rect(image, Vector2i(14, 9 + bob), Vector2i(2, 2), EYE)

	return ImageTexture.create_from_image(image)


func _fill_rect(image: Image, at: Vector2i, size: Vector2i, color: Color) -> void:
	for y in range(at.y, min(at.y + size.y, FRAME_SIZE)):
		for x in range(at.x, min(at.x + size.x, FRAME_SIZE)):
			image.set_pixel(x, y, color)


func _add_strip(frames: SpriteFrames) -> void:
	highlight = ColorRect.new()
	highlight.color = Color('#2a2f3d')
	highlight.size = Vector2(STRIP_STEP, STRIP_STEP)
	highlight.position = Vector2(_strip_x(0) - STRIP_STEP * 0.5, STRIP_Y - STRIP_STEP * 0.5)
	add_child(highlight)

	for i in FRAME_COUNT:
		var thumb: Sprite2D = Sprite2D.new()
		thumb.texture = frames.get_frame_texture('default', i)
		thumb.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST
		thumb.scale = Vector2(3, 3)
		thumb.position = Vector2(_strip_x(i), STRIP_Y)
		add_child(thumb)


func _strip_x(index: int) -> float:
	return 640.0 + (index - (FRAME_COUNT - 1) * 0.5) * STRIP_STEP


func _add_background() -> void:
	var background: ColorRect = ColorRect.new()
	background.color = Color('#12141a')
	add_child(background)
	background.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)


func _add_label(text: String, at: Vector2) -> void:
	var label: Label = Label.new()
	label.text = text
	label.position = at
	label.add_theme_color_override('font_color', Color('#999999'))
	add_child(label)

Plus d'exemples de Animation