用代码生成精灵帧
启动时在 Image 缓冲区里绘制的八帧行走循环,交给 AnimatedSprite2D 播放。底部那条就是 SpriteFrames 本身。
上方的编辑器正在运行这个项目。改一行代码,它就会重新加载。
用到的 Godot 类
AnimatedSprite2DSpriteFramesImageTexture
代码
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)