docsReading time: 3 minutes


Animation Controller

The AnimationController manages which spritesheet animation is displayed for an entity. It determines the current animation based on entity state and handles animation playback.

How Animation Works

  1. Entity has a spritePrefix (e.g., “gurknukem”)
  2. Spritesheets follow naming convention: {prefix}-{state}-{direction}.png
  3. AnimationController selects appropriate spritesheet based on entity state
  4. RenderEngine displays the current animation frame

CreatureAnimationController

For Creature entities, LITIENGINE provides CreatureAnimationController with built-in animation rules:

Spritesheet Naming Convention

{spritePrefix}-{state}-{direction}.{extension}

Examples:

  • gurknukem-idle-left.png – Idle animation, facing left
  • gurknukem-walk-left.png – Walking animation, facing left
  • gurknukem-dead.png – Death animation (no direction)

Default States

  • idle – Entity is standing still
  • walk – Entity is moving
  • dead – Entity has died

Automatic Flipping

By default, horizontal flip fallback is enabled. You only need sprites for left OR right direction:

// Only need gurknukem-walk-left.png
// gurknukem-walk-right.png is auto-generated by flipping

Custom Animation Controller

Create custom controllers for complex animation logic:

public class PlayerAnimationController extends CreatureAnimationController<Player> {

  public PlayerAnimationController(Player entity) {
    super(entity);

    // Add custom animation rule
    this.addRule(this::shouldAttack, this::getAttackAnimation);
  }

  private boolean shouldAttack() {
    return getEntity().isAttacking();
  }

  private String getAttackAnimation() {
    String dir = getEntity().getFacingDirection().name().toLowerCase();
    return "attack-" + dir;
  }
}

Animation Rules

Add rules to determine when specific animations play:

// Add a rule: condition -> animation name
animationController.addRule(
  () -> entity.isJumping(),           // Condition
  () -> "jump-" + getDirection()      // Animation name
);

// Rules are evaluated in order of priority
animationController.addRule(1, condition, animation); // Higher priority
animationController.addRule(0, condition, animation); // Lower priority

Playing Animations

// Play specific animation
entity.getAnimationController().play("custom-animation");

// Play with loop
entity.getAnimationController().play("walk", true);

// Check if animation is playing
boolean isPlaying = entity.getAnimationController().isPlaying("attack");

Animation Events

Listen for animation keyframes:

entity.getAnimationController().onKeyFrameChanged((anim, frame) -> {
  // Handle keyframe change
  if (frame == 3) {
    playSound("footstep.wav");
  }
});

Accessing Current Animation

Animation current = entity.getAnimationController().getCurrentAnimation();

if (current != null) {
  String name = current.getName();
  int frame = entity.getAnimationController().getCurrentKeyFrameIndex();
  int totalFrames = current.getTotalFrames();
}

Spritesheet Requirements

For proper animation:

  1. Frame dimensions must be set correctly in utiLITI
  2. Frame duration controls animation speed (milliseconds per frame)
  3. Loop setting determines if animation repeats

In utiLITI

  1. Select spritesheet in Resources panel
  2. Edit sprite dimensions (width x height per frame)
  3. Set frame duration
  4. Enable/disable loop

Registering Animations

// Animations are auto-registered from spritesheets
// Or manually register:
Spritesheet sheet = Resources.spritesheets().get("player-idle");
Animation anim = new Animation(sheet, true, 100); // loop=true, duration=100ms
entity.getAnimationController().add(anim);

See Also


steffen-wilkeLast updated 1 day ago

On this page