PixelSprite2D
Extends AnimatedSprite2D. Read from the plugin's source on every build.
A node that draws a document. Set document and that is the whole of
it: no export, no texture to build, nothing to keep in step by hand.
The front door. PixelSpriteTexture and PixelSpriteFrames are underneath
and stay useful on their own — a TextureRect, a TileSet, anything that
wants artwork without being a sprite — but finding them means knowing to look
inside a Texture slot for a resource type you have not heard of. This is in
the Create Node dialog under its own name.
An AnimatedSprite2D rather than a Sprite2D even for a still, because a
document with one frame can grow a second. A node built on a plain texture
stops being right at that moment and says nothing about it: the artwork gains
an animation and the sprite goes on showing frame one, which is a bug you
find by wondering why nothing moves. One frame here is an animation of one
frame, and the second frame plays.
Properties
document
@export var document: PixelDocumentThe document this node draws: its frames are built from it, and rebuilt as it changes.
preview_in_editor
@export var preview_in_editor: bool = trueWhether the animation runs in the editor as well as in the game.
autoplay only means anything once the scene is running: the editor does not
tick a node in the scene you are editing, so an AnimatedSprite2D sits on frame
zero until you press play. This script is a @tool, which means it can run
its own clock and show you the animation while you are building the scene —
which is the whole reason for drawing against a document rather than an
export.
Off makes the node static in the editor and changes nothing about the game.
saved_animation
@export_storage var saved_animation: StringNameWhich animation the scene keeps for this node, and why animation itself
is not stored.
A scene writes a node’s engine properties before its script and reads them
back in that order, so a stored animation reaches a bare AnimatedSprite2D
with an empty frames slot. The engine refuses the name with “There is no
animation with name”, clears it, and only then attaches this script and the
document. Every scene the editor saves does that, and so does every scene an
export re-packs: one error per PixelSprite2D on load, and a name that was not
the first tag came back as the first tag. Nothing on this script can run
before that first assignment, so the name travels as a property of the
script instead, written after document and read back after it, once the
frames hold the tags.
Read, it is animation as it stands. Set, it plays the animation named when
the frames have it, and is otherwise dropped, which is what the engine does
with a name its frames do not hold. Not offered in the inspector: animation
is where a person picks it.
Methods
set_document
func set_document(value: PixelDocument) -> voidSets document and builds the frames from it, once, however the
property was assigned.
path_changed
static func path_changed(document: PixelDocument) -> intPuts document, just read off disk again, on every live node drawing
the file it came from, and answers how many there were. Each keeps the
animation and the frame it was on; see swap_document.
After PixelSpriteFrames.path_changed, never before: that one
queues the rebuild of the frames this node holds, and the rebuild here
does it now and clears the queue, so the animation is composited once.
swap_document
func swap_document(value: PixelDocument) -> voidTakes value in place of the document held and keeps the animation
and the frame the node was on, where the new document still has them; an
animation it no longer describes falls back the way a load does, to the
first tag.
The same instance is the ordinary case. The listener reloads with
CACHE_MODE_REPLACE, which refills the instance this node holds, so the
frames are rebuilt in place. Rebuilding clears every animation before it
adds the frames back, and an AnimatedSprite2D whose frames were cleared
under it is on frame zero, which is why the frame is read before and put
back after.
rebuild
func rebuild() -> voidBuilds the frames from the document again, now.
PixelSpriteTexture and PixelSpriteFrames have the same call, and it is
here for the same reason: the frames follow the document’s own signals, but a
caller that has changed the document behind them can ask. That is what
PixelDocument.recolor and anything else reaching into the cels from
game code wants after it has finished.
Following the signals is coalesced to the next idle frame, so this is also how a game gets the new pixels on screen inside the frame it changed them in. It composites every frame of every animation the document describes.
set_preview_in_editor
func set_preview_in_editor(value: bool) -> voidSets preview_in_editor and starts or stops the preview clock to
match.
advance_preview
func advance_preview(delta: float) -> voidOne step of that clock. Separate from _process because the editor check
belongs at the edge: Engine.is_editor_hint() is false in a script run, so a
_process that tested it was a _process no test could reach.
Constants
HIDDEN_PROPERTIES
const HIDDEN_PROPERTIES: Array[StringName] = [&"frame", &"frame_progress"]Where the animation currently is, which is a reading rather than a setting.
Both are the preview clock’s output: a node ticking in the editor moves them
several times a second, so a spin box over either is a control fighting the
thing it controls. The frame is picked by playing an animation — the
SpriteFrames panel below is where an AnimatedSprite2D is driven by hand, and
sprite_frames stays visible so that panel stays reachable.
Still stored exactly as AnimatedSprite2D stores them, less what
_hide_from_storage takes off a frame the clock moved.
frame is the one this takes away; the engine already withholds
frame_progress, which is listed so it stays withheld if that ever moves.
JamChip 0.1.0, by GlitterSnack. MIT licence. Built from the source on every merge, artwork and screenshots included, with JamChip.