Skip to content

Enemy Animation Sprites

Logan Booth edited this page Oct 20, 2026 · 6 revisions

Enemy Animation

Part of the Enemies feature. Ticket: New Enemy Sprites.

Overview

Enemies are drawn with an AnimationRenderComponent backed by a libGDX texture atlas. EnemyAnimationController chooses the animation from the enemy's state. This page covers the atlas format, how each enemy is sized and animated, and how to add animations for a new enemy.

Atlas format

Each enemy has a .atlas file and a PNG sheet in assets/images/enemies/.

Region Purpose
default Required. scaleEntity() fails without it. It points at the idle frame.
walk Looping walk cycle, one region per frame, indexed from 0.
idle A single frame. It points at the middle walk frame, so nothing is duplicated in the PNG.
attack / sweep / hurt / laser Optional, one-shot animations, only for the enemies that use them.

Notes:

  • All frames of one enemy sit on the same canvas size, with the feet on a shared baseline and the body at a shared pivot. This stops the sprite jittering or shifting when it flips to face the player.
  • Filtering is Nearest,Nearest, so pixel art stays sharp.
  • Region names are global within an atlas file. Use the same names across enemies, but keep one default per file.

Enemies

Enemy Atlas Animations Frame size (px)
Skeleton warrior skeleton_warrior.atlas walk (5), attack (5), idle 346×316
Skeleton archer skeleton_archer.atlas walk (12), idle 300×392
Necromancer necromancer.atlas walk (10), idle 308×392
Calypso calypso.atlas idle, walk, sweep, hurt, laser see EnemyFactory

Skeleton warrior

Plays attack when SweepAttackTask fires attackStart. The frame time is chosen so the thrust frame is showing when the hit lands

Skeleton archer and necromancer

Walk and idle only so they have no attack animation.

Calypso

  • sweep is her melee attack and plays on attackStart.
  • hurt plays when she takes damage.
  • laser is her phase 2 attack. TimerAttackTask fires laserStart, winds up for 0.6s, then spawns a beam entity textured with images/projectiles/calypso_laser_beam.png. It fires laserEnd when it finishes

Sizing and anchors

Frames sit on a wide canvas, for example to fit the warrior's sword thrust or the archer's bow. So EnemyFactory does this for each enemy:

  1. Calls animator.scaleEntity().
  2. Works out the on-screen character height from the player's height.
  3. Scales the entity to the canvas using body height in pixels, so the character, not the canvas, matches the target height.
  4. Sizes the collider and hitbox to the body so empty sprite space can't hurt the player. Each addAnimation(...) call takes an anchor (x, y in pixels) that matches the pivot in the atlas. This keeps the sprite in place when it mirrors.

Animation controller

EnemyAnimationController listens for events and picks the animation:

  • Moving selects walk, stopped selects idle.
  • attackStart plays sweep if the enemy has one, otherwise attack.
  • While an attack animation plays, walk and idle are held until it finishes.
  • It flips the sprite with setFlipX so the enemy faces the player.

Adding animations for a new enemy

  1. Clean and repack the sheet onto a uniform grid with the feet aligned.
  2. Create the .atlas with default, walk and idle, plus any extras.
  3. Add both files to assets/images/enemies/ and register the atlas in the game area's asset list.
  4. In the createX method, add an AnimationRenderComponent, the animations with anchors, and an EnemyAnimationController.
  5. Size the entity from the player's height and shrink the collider and hitbox to the body.

Asset credits and AI use

The base sprite art for the skeleton warrior, skeleton archer, necromancer and Calypso was generated with ChatGPT, then edited by the team.

Asset Generated with Our changes
Enemy walk and attack sheets ChatGPT Background removal, frame alignment, repacking onto a uniform grid
Calypso laser and hurt sheets, beam sprite ChatGPT Background removal, beam cut out of the burst frame, rescaled to match the walk sheet

The animation code, atlases and sizing logic in EnemyFactory were written by the team.

Clone this wiki locally