Animation Tutorial

This tutorial shows how to author clips and controllers in the AxisPy editor UI, attach them to an entity, and drive animations from scripts using triggers and state changes.

What you will build

  • A looping Idle and Run clip from a spritesheet.

  • A controller with states and transitions.

  • An entity that plays Idle on start and switches to Run while a key is held.

Requirements

Create clips in the Editor (Clip Editor)

  1. Open the Animation Editor tab

  • Main Window → “Animation Editor” tab (or Asset Manager → right‑click a clip → Open Animation Clip).

  1. Create a new clip file (.anim)

  • Asset Manager → right‑click a folder → “New Animation Clip”.

  • Name it e.g. idle.anim or run.anim.

  1. Configure the clip

  • In the Clip Editor:

    • Set FPS and Loop.

    • Choose Type: - Spritesheet: set sheet_path, frame_width/height, margin and spacing. - Image Sequence: add image_paths (one per frame).

    • Preview updates live; click “Save” to write the .anim via the editor.

Create a controller (.actrl) and add states/transitions

  1. Create controller

  • Asset Manager → right‑click a folder → “New Animation Controller”. Name it e.g. player.actrl.

  • Double‑click to open it in the Controller view.

  1. Add states (nodes) and assign clips

  • Click “Add Node”. Select the node to edit its properties.

  • Click the “…” next to “Clip (.anim)” and choose your clip (e.g. idle.anim).

  • The node’s preview plays in the right panel.

  • Repeat for run.anim.

  1. Set default state

  • Draw a transition from Root to your default node (double‑click a node, then click the target node). The editor stores a single Root→Default edge.

  1. Add transitions between states

  • Double‑click a node, then click another to connect.

  • Select the arrow (edge) to edit properties: - Trigger: a string (e.g. start_run) you’ll fire from scripts. - On Finish: when checked, transition fires after the source clip reaches its last frame (non‑looping).

  • Save the controller (toolbar “Save”).

Attach to an entity (Inspector)

  • Ensure the entity has a Transform and a SpriteRenderer.

  • Add AnimatorComponent. - Set controller_path to your .actrl (relative to the project folder works; the engine also resolves by controller/clip folder and AXISPY_PROJECT_PATH). - Optional: set play_on_start and speed.

Drive animation from a script (Script Editor)

Use the script editor tab to add logic. The AnimationSystem will hot‑reload controller/clip files while the game runs.

from core.components import AnimatorComponent
import pygame
from core.input import Input

class PlayerAnim:
    def on_start(self):
        self.anim = self.entity.get_component(AnimatorComponent)
        # Optionally force a state at startup
        if self.anim and self.anim.controller:
            default = self.anim.controller.get_default_state()
            if default:
                self.anim.play(default, restart=True)

    def on_update(self, dt: float):
        if not self.anim:
            return
        # Fire a trigger defined on a transition from the current state
        if Input.get_key(pygame.K_LSHIFT):
            self.anim.set_trigger("start_run")
        else:
            self.anim.set_trigger("stop_run")

Control API quick reference

  • anim.play(state_name, restart=False) — jump to a node by name.

  • anim.set_trigger(name) — enqueue a trigger; consumed by the system if a matching transition exists.

  • anim.pause() / anim.resume() / anim.stop(reset=False) — playback control.

  • anim.speed — global speed multiplier (affects FPS).

  • anim.current_state / anim.is_playing / anim.is_paused — status.

How transitions resolve (runtime)

  • On each frame, the system: - Reloads controller if the file changed (hot reload). - If no current state, uses the controller’s Root→Default. - Checks transitions out of the current state. If a transition has trigger and that trigger was set (and not yet consumed), it switches immediately. - When a non‑looping clip reaches its last frame, any transition from the current state with on_finish is taken. - The current frame is assigned to the entity’s SpriteRenderer.

Tips and troubleshooting

  • If you don’t see frames: ensure the entity has a SpriteRenderer, and your .anim clip resolves its images/spritesheet correctly (paths are project‑relative in the editor; engine resolves via controller/clip folder, project root, or CWD).

  • To flip sprites, use negative Transform scale values.

  • To keep multiple triggers around, call set_trigger each frame you need them. Triggers are “consumed” the next time the system sees a matching transition.

  • Editor previews do not require the game to be running; runtime playback will match FPS/loop/segment settings.