Tile Animation System — Architecture Diagram
System Overview
Component Roles
| Component | Responsibility |
|---|---|
| Scene | Owns the animation manager and controls update flow |
| Renderer | Draws tilemaps and resolves animation frames |
| TileMapGeneric | Stores tile indices and tileset references |
| AnimationManager | Updates animation state and manages lookup table |
| LookupTable | Fast remapping from tile index → animated frame |
| Tileset | Static tile graphics stored in PROGMEM |
Data Flow
Initialization (Scene::init)
1. Scene creates TileAnimationManager
├─ Reads TileAnimation[] from PROGMEM
├─ Initializes lookupTable[MAX_TILESET_SIZE]
└─ Sets identity mapping (i → i), then rebuilds animated ranges for frame 0
2. Scene links manager to tilemap
└─ backgroundLayer.animManager = &animManagerAfter initialization:
Tilemap indices → AnimationManager → TilesetUpdate Loop (Scene::update)
Key properties:
• deterministic update cost when the lookup rebuilds (same as before) • no dynamic allocations • small constant runtime; pacing decoupled from main-loop iteration rate
Render Loop (Scene::draw)
Animation integration cost:
1 array lookup per tileMemory Layout
PROGMEM (Flash)
Animation definitions are stored in flash.
TileAnimation animations[] =
{
{ baseTile: 42, frameCount: 4, frameDuration: 8, reserved: 0 },
{ baseTile: 46, frameCount: 2, frameDuration: 6, reserved: 0 }
};Memory cost:
4 bytes × animationCountExample:
8 animations = 32 bytesRAM Allocation
TileAnimationManageranimations pointer 4 bytes
animCount 1 byte
tileCount 2 bytes (uint16_t - soporta 512+ tiles)
globalFrameCounter 2 bytes
lookupTable[N] N bytesTotal RAM usage:
N + 9 bytesValidación:
- Compile-time:
static_assert(MAX_TILESET_SIZE >= 64) - Runtime (debug): Verifica
tileCount <= MAX_TILESET_SIZE
Example:
N = 256 tiles
Total = 265 bytes RAMLookup Table Mechanics
Animation Model
PixelRoot32 uses a single-frame remap model:
All tiles in an animation range always point to the same current frame.
This matches the behaviour used in many retro engines.
Initial State (Identity Mapping)
lookupTable[0] = 0
lookupTable[1] = 1
...
lookupTable[42] = 42
lookupTable[43] = 43
lookupTable[44] = 44
lookupTable[45] = 45Animation Example
Water animation (frameDuration = 8 logical ticks at ~60 Hz ≈ 133 ms per animation cell):
baseTile = 42
frameCount = 4
frameDuration = 8Frames stored in tiles:
42 43 44 45Logical ticks 0–7 (counter 0–7)
currentFrame = (counter / 8) % 4 = 0
currentTile = 42lookupTable[42] = 42
lookupTable[43] = 42
lookupTable[44] = 42
lookupTable[45] = 42Logical ticks 8–15 (counter 8–15)
currentFrame = 1
currentTile = 43lookupTable[42] = 43
lookupTable[43] = 43
lookupTable[44] = 43
lookupTable[45] = 43Logical ticks 16–23 (counter 16–23)
currentFrame = 2
currentTile = 44lookupTable[42] = 44
lookupTable[43] = 44
lookupTable[44] = 44
lookupTable[45] = 44Logical ticks 24–31 (counter 24–31)
currentFrame = 3
currentTile = 45lookupTable[42] = 45
lookupTable[43] = 45
lookupTable[44] = 45
lookupTable[45] = 45Loop
After frame 31:
currentFrame = 0The animation repeats.
Rendering Pipeline
Performance Characteristics
Time Complexity
Operation Complexity Typical Time
--------------------------------------------
Constructor O(N) ~50 µs
step() O(A × F) ~3–7 µs
resolveFrame() O(1) ~0.02 µs
reset() O(N) ~50 µsWhere:
N = tileCount
A = animation count
F = frames per animationSpace Complexity
Component Size Location
-------------------------------------------
TileAnimation[] 4 × A PROGMEM
lookupTable N bytes RAM
animations pointer 4 bytes RAM
animCount 1 byte RAM
tileCount 2 bytes RAM
globalFrameCounter 2 bytes RAMTotal RAM:
N + 9 bytesExample:
256 tiles → 265 bytes RAMConfiguration Matrix
MAX_TILESET_SIZE | RAM Usage
-----------------|-----------
64 | 73 bytes
128 | 137 bytes
256 | 265 bytes
512 | 521 bytesNote:
tileCount is uint16_tThis allows expansion beyond 256 tiles in future versions.
Retro Console Comparison
NES
Animation method:
CHR bank switchingPixelRoot32 equivalent:
lookup table remappingSNES
Animation method:
VRAM updates during VBlankPixelRoot32 equivalent:
AnimationManager::step() during update phaseGame Boy Advance
Animation method:
VRAM tile updatesPixelRoot32 advantage:
No VRAM writes required
Only an array lookupSummary
Architecture characteristics:
Memory: ~265 bytes RAM
CPU overhead: <0.2%
Allocations: zero
Lookup cost: O(1)
Integration: minimal changesResult:
Production-ready tile animation system
optimized for ESP32-class hardwareRelated Documentation
Framebuffer Optimization (v1.2.2+)
For additional rendering optimizations, see Architecture Index:
shouldRedrawFramebuffer(): Scene method that conditionally skipsdraw()andpresent()calls when visual state hasn't changed, reducing unnecessary rendering.getVisualSignature(): Visual signature computation to efficiently detect framebuffer changes and avoid redundant redraws.
See ARCHITECTURE.md - Rendering Pipeline for details.
