simvx.core.animation.sprite¶
Sprite nodes with frame-based animation support.
Module Contents¶
Classes¶
2D sprite node – renders a texture via Draw2D.draw_texture_region(). |
|
Named sprite animation with frame range. |
|
Sprite with frame-based animation from sprite sheets. |
API¶
- class simvx.core.animation.sprite.Sprite2D(texture: Any = None, position=None, rotation: float = 0.0, scale=None, colour: tuple = (1.0, 1.0, 1.0, 1.0), width: int | None = None, height: int | None = None, filter: str = 'linear', flip_h: bool = False, flip_v: bool = False, **kwargs)[source]¶
Bases:
simvx.core.graphics.texture_slot.TextureSlot,simvx.core.nodes_2d.node2d.Node2D2D sprite node – renders a texture via Draw2D.draw_texture_region().
The
textureproperty takes a file path, encoded bytes, an RGBA ndarray, a live offscreen target (aSubViewportor aRenderView), or a- Class:
~simvx.core.graphics.Textureresource. The graphics backend resolves it through TextureManager and hands the resulting handle back via- Meth:
~simvx.core.graphics.TextureSlot.publish_texture_slot. Thedraw()callback emits a textured quad through the renderer (Draw2D).
Reassigning
texturere-resolves: the cached handle is dropped and the next frame shows the new image. Wrap the source in aTexturewhen the PIXELS change rather than the source, and callupdate().A live offscreen target is sampled in display range, not scene range. A
SubViewportrenders to a float target so that 3D content inside it keeps its high-dynamic-range values, but a sprite reads it through the ordinary 8-bit sprite path, so anything the offscreen scene renders brighter than 1.0 is clipped at 1.0 when a sprite samples it, and the result is quantised to 8 bits per channel. The same feed used as a 3D material stays in scene range and is tone-mapped with the rest of the frame, so the two can differ for an HDR-bright source. Author a SubViewport that a sprite samples to land inside 0..1 – which is what UI, minimaps, portals and camera feeds already do.Attributes: texture: Path to the image file (PNG/JPG). colour: RGBA tint (0.0-1.0 floats). width: Display width in pixels, or
Nonefor the texture’s native width. height: Display height in pixels, orNonefor the texture’s native height.Noneis how a sprite asks for the native size; any other value is a literal pixel count, so0is a zero-area quad and not a request for anything. (A0read back out of a save written when that was how a sprite asked for its native size loads asNone; see :meth:from_dict.) Read :attr:draw_sizewhen what you want is the size on screen, since that answers in pixels whichever way the sprite was set up.Initialization
- frames_h¶
1
- frames_v¶
1
- texture¶
‘Property(…)’
- colour¶
‘Colour(…)’
- width¶
‘Property(…)’
- height¶
‘Property(…)’
- filter¶
‘Property(…)’
- flip_h¶
‘Property(…)’
- flip_v¶
‘Property(…)’
- property draw_size: simvx.core.math.types.Vec2[source]¶
Pixel size of the quad this sprite draws, before
scale.width/heightwhen both are set, otherwise the texture’s native dimensions (one cell of the grid for a sprite sheet). Read this instead ofwidth/heightwhen you need the size on screen: those two stayNonefor a native-size sprite, whereas this always answers in pixels. Hit-testing, editor gizmos and layout code want this one.
- on_draw(renderer) None[source]¶
Emit a textured quad via the renderer (Draw2D).
flip_h/flip_vflip the source UV rectangle rather than the node’s scale, so the sprite pivot stays atworld_position(the Godot semantics ports rely on).
- property texture_slot: int¶
- publish_texture_slot(slot: int) None¶
- publish_overlay_slot(slot: int) None¶
- strict_errors: ClassVar[bool]¶
True
- dev_checks: ClassVar[bool]¶
None
- script_error_raised¶
‘Signal(…)’
- dynamic: bool¶
False
- visible¶
‘Property(…)’
- update_mode¶
‘Property(…)’
- __properties__: ClassVar[dict[str, simvx.core.descriptors.Property]]¶
None
- classmethod __init_subclass__(**kwargs)¶
- property name: str¶
- property visible_in_tree: bool¶
- reset_error() None¶
- add_child(node: simvx.core.node.T) simvx.core.node.T¶
- remove_child(node: simvx.core.node.Node) None¶
- reparent(new_parent: simvx.core.node.Node)¶
- node_at(path, default=_NO_DEFAULT)¶
- find(target, *, direct: bool = False)¶
- find_all(target, *, direct: bool = False)¶
- expect(target, *, direct: bool = False)¶
- ancestor(target)¶
- walk(*, include_self: bool = True) collections.abc.Iterator[simvx.core.node.Node]¶
- property path: str¶
- property is_scene_root: bool¶
- add_to_group(group: str)¶
- remove_from_group(group: str)¶
- is_in_group(group: str) bool¶
- on_ready() None¶
- on_enter_tree() None¶
- on_exit_tree() None¶
- on_update(dt: float) None¶
- on_fixed_update(dt: float) None¶
- on_picked(event: simvx.core.events.InputEvent) None¶
- on_unhandled_input(event: simvx.core.events.TreeInputEvent) None¶
- start_coroutine(gen: simvx.core.descriptors.Coroutine) simvx.core.descriptors.CoroutineHandle¶
- stop_coroutine(gen_or_handle)¶
- queue_redraw() None¶
- property render_dirty: bool¶
- clear_children()¶
- destroy()¶
- property destroying: bool¶
- call_deferred(method: collections.abc.Callable[..., Any], *args: Any) None¶
- property app¶
- property tree: simvx.core.scene_tree.SceneTree¶
- property physics¶
- property physics_2d¶
- __getitem__(key: str)¶
- classmethod get_properties() dict[str, simvx.core.descriptors.Property]¶
- __repr__()¶
- position¶
‘_SpatialVecProperty(…)’
- rotation¶
‘Property(…)’
- scale¶
‘_SpatialVecProperty(…)’
- z_index¶
‘Property(…)’
- z_as_relative¶
‘Property(…)’
- render_layer¶
‘Property(…)’
- set_render_layer(index: int, enabled: bool = True) None¶
- is_on_render_layer(index: int) bool¶
- property absolute_z_index: int¶
- property rotation_degrees: float¶
- property world_position: simvx.core.math.types.Vec2¶
- property world_rotation: float¶
- property world_scale: simvx.core.math.types.Vec2¶
- property world_transform: tuple[simvx.core.math.types.Vec2, simvx.core.math.types.Vec2, float]¶
- property forward: simvx.core.math.types.Vec2¶
- property right: simvx.core.math.types.Vec2¶
- translate(offset: tuple[float, float] | numpy.ndarray)¶
- rotate(radians: float)¶
- rotate_deg(degrees: float)¶
- look_at(target: tuple[float, float] | numpy.ndarray)¶
- transform_points(points: list[simvx.core.math.types.Vec2]) list[simvx.core.math.types.Vec2]¶
- draw_polygon(renderer, points: list[simvx.core.math.types.Vec2], closed=True, colour=None)¶
- wrap_screen(margin: float = 20)¶
- hdr¶
‘Property(…)’
- property transform_render_dirty: bool¶
- class simvx.core.animation.sprite.SpriteAnimation[source]¶
Named sprite animation with frame range.
- name: str¶
None
- frames: list[int]¶
None
- fps: float¶
10.0
- loop: bool¶
True
- class simvx.core.animation.sprite.AnimatedSprite2D(**kwargs)[source]¶
Bases:
simvx.core.animation.sprite.Sprite2DSprite with frame-based animation from sprite sheets.
Inherits from Sprite2D (Node2D), so it participates in the scene tree and gets
on_update(dt)andon_draw(renderer)called automatically.The sheet grid, the registered animations and whether playback runs are authoring state, so they are Properties and a saved scene carries them. The playback position (
frame,frame_time) is not: a reloaded scene is the sprite that was set up, not the instant a save happened to catch.Example: sprite = AnimatedSprite2D( texture=”player.png”, frames_h=4, frames_v=4 ) sprite.add_animation(“walk”, frames=[0, 1, 2, 3], fps=10, loop=True) sprite.add_animation(“jump”, frames=[4, 5, 6], fps=15, loop=False) sprite.play(“walk”)
Initialization
- frames_h¶
‘Property(…)’
- frames_v¶
‘Property(…)’
- frame_width¶
‘Property(…)’
- frame_height¶
‘Property(…)’
- animations¶
‘Property(…)’
- current_animation¶
‘Property(…)’
- playing¶
‘Property(…)’
- __transient__¶
‘frozenset(…)’
- add_animation(name: str, frames: list[int], fps: float = 10.0, loop: bool = True)[source]¶
Register a named animation.
- stop()[source]¶
Stop animation and reset to the start of the current animation.
playingbecomesFalseand the frame counter resets so a subsequentplay()orresume()begins from frame 0.
- pause()[source]¶
Pause animation, preserving the current frame and frame time.
playingbecomesFalsebut no state is reset;resume()continues from where playback left off.
- on_draw(renderer) None[source]¶
Draw the current animation frame as a textured quad with proper UVs.
flip_h/flip_v(inherited fromSprite2D) swap the UV endpoints: pivot remains atworld_positionregardless.The texture resolves through the same path as
Sprite2D, so a live offscreen source (aSubViewport, aRenderView) draws the live feed rather than nothing. The frame grid is a plain UV sub-rectangle of whatever is bound, so the default 1x1 grid samples the whole viewport and a larger grid slices it exactly as it slices a sprite sheet. Left at native size, the quad is the viewport’s own resolution divided by that grid, and it tracks the viewport if it is resized.
- property frame_uv: tuple[simvx.core.math.types.Vec2, simvx.core.math.types.Vec2][source]¶
UV coordinates for the current frame (top-left, bottom-right).
- classmethod from_frames(frames: list[Any] | str | pathlib.Path, fps: float = 10.0, *, name: str = 'default', loop: bool = True, play: bool = True, **kwargs) simvx.core.animation.sprite.AnimatedSprite2D[source]¶
Build a flipbook AnimatedSprite2D from a list of frame textures or a folder.
framesaccepts any of: *list: each element is a per-frame texture source (file path, PNG bytes, orH×W×4uint8 ndarray). Frames are stitched into a single horizontal strip atlas. *str/Pathto a directory: every*.png(recursive: no, top-level only) is sorted alphabetically and treated as one frame. An empty directory or no PNG files raisesFileNotFoundError.The resulting sprite uses a single sheet texture (so it follows the same fast GPU path as a hand-authored atlas: no per-frame upload at runtime) with
frames_h = N,frames_v = 1. The animation namednameis registered with all N frames;play=Truestarts playback immediately.All frames must have the same pixel dimensions; mismatched sizes raise
ValueError.
- texture¶
‘Property(…)’
- colour¶
‘Colour(…)’
- width¶
‘Property(…)’
- height¶
‘Property(…)’
- filter¶
‘Property(…)’
- flip_h¶
‘Property(…)’
- flip_v¶
‘Property(…)’
- property draw_size: simvx.core.math.types.Vec2¶
- property texture_slot: int¶
- publish_texture_slot(slot: int) None¶
- publish_overlay_slot(slot: int) None¶
- strict_errors: ClassVar[bool]¶
True
- dev_checks: ClassVar[bool]¶
None
- script_error_raised¶
‘Signal(…)’
- dynamic: bool¶
False
- visible¶
‘Property(…)’
- update_mode¶
‘Property(…)’
- __properties__: ClassVar[dict[str, simvx.core.descriptors.Property]]¶
None
- classmethod __init_subclass__(**kwargs)¶
- property name: str¶
- property visible_in_tree: bool¶
- reset_error() None¶
- add_child(node: simvx.core.node.T) simvx.core.node.T¶
- remove_child(node: simvx.core.node.Node) None¶
- reparent(new_parent: simvx.core.node.Node)¶
- node_at(path, default=_NO_DEFAULT)¶
- find(target, *, direct: bool = False)¶
- find_all(target, *, direct: bool = False)¶
- expect(target, *, direct: bool = False)¶
- ancestor(target)¶
- walk(*, include_self: bool = True) collections.abc.Iterator[simvx.core.node.Node]¶
- property path: str¶
- property is_scene_root: bool¶
- add_to_group(group: str)¶
- remove_from_group(group: str)¶
- is_in_group(group: str) bool¶
- on_ready() None¶
- on_enter_tree() None¶
- on_exit_tree() None¶
- on_fixed_update(dt: float) None¶
- on_picked(event: simvx.core.events.InputEvent) None¶
- on_unhandled_input(event: simvx.core.events.TreeInputEvent) None¶
- start_coroutine(gen: simvx.core.descriptors.Coroutine) simvx.core.descriptors.CoroutineHandle¶
- stop_coroutine(gen_or_handle)¶
- queue_redraw() None¶
- property render_dirty: bool¶
- clear_children()¶
- destroy()¶
- property destroying: bool¶
- call_deferred(method: collections.abc.Callable[..., Any], *args: Any) None¶
- property app¶
- property tree: simvx.core.scene_tree.SceneTree¶
- property physics¶
- property physics_2d¶
- __getitem__(key: str)¶
- classmethod get_properties() dict[str, simvx.core.descriptors.Property]¶
- __repr__()¶
- position¶
‘_SpatialVecProperty(…)’
- rotation¶
‘Property(…)’
- scale¶
‘_SpatialVecProperty(…)’
- z_index¶
‘Property(…)’
- z_as_relative¶
‘Property(…)’
- render_layer¶
‘Property(…)’
- set_render_layer(index: int, enabled: bool = True) None¶
- is_on_render_layer(index: int) bool¶
- property absolute_z_index: int¶
- property rotation_degrees: float¶
- property world_position: simvx.core.math.types.Vec2¶
- property world_rotation: float¶
- property world_scale: simvx.core.math.types.Vec2¶
- property world_transform: tuple[simvx.core.math.types.Vec2, simvx.core.math.types.Vec2, float]¶
- property forward: simvx.core.math.types.Vec2¶
- property right: simvx.core.math.types.Vec2¶
- translate(offset: tuple[float, float] | numpy.ndarray)¶
- rotate(radians: float)¶
- rotate_deg(degrees: float)¶
- look_at(target: tuple[float, float] | numpy.ndarray)¶
- transform_points(points: list[simvx.core.math.types.Vec2]) list[simvx.core.math.types.Vec2]¶
- draw_polygon(renderer, points: list[simvx.core.math.types.Vec2], closed=True, colour=None)¶
- wrap_screen(margin: float = 20)¶
- hdr¶
‘Property(…)’
- property transform_render_dirty: bool¶