From dd2a24f623f70833572a2a996c8e8eea8bf0f9b4 Mon Sep 17 00:00:00 2001 From: John McCardle Date: Sat, 7 Feb 2026 22:15:31 +0000 Subject: [PATCH] Update Animation System wiki with .animate() method, Easing enum, verified properties, callback signature --- Animation-System.md | 407 +++++++++++++++++++++++++++----------------- 1 file changed, 248 insertions(+), 159 deletions(-) diff --git a/Animation-System.md b/Animation-System.md index 5dafe1d..658a27f 100644 --- a/Animation-System.md +++ b/Animation-System.md @@ -1,159 +1,248 @@ -# Animation System - -The Animation System provides property-based animations with 24+ easing functions for smooth transitions on all UI elements. - -## Quick Reference - -**Related Issues:** -- [#120](../issues/120) - Animation Property Locking (Tier 1 - Active) -- [#119](../issues/119) - Animation Completion Callbacks (Closed - Implemented) -- [#100](../issues/100) - Add Rotation Support - -**Key Files:** -- `src/AnimationManager.h` / `src/AnimationManager.cpp` - Animation execution engine -- `src/Animation.h` - Base Animation class -- `src/UIDrawable.h` - Animatable properties defined here - -**API Reference:** -- See [mcrfpy.animate()](../docs/api_reference_dynamic.html#animate) in generated API docs - -## Architecture Overview - -### Property-Based Animation - -Animations modify any numeric property on UI objects over time: - -```python -import mcrfpy - -sprite = mcrfpy.Sprite("player.png", 100, 100) - -# Animate position with easing -mcrfpy.animate(sprite, "x", 300, 1000, "ease_in_out_cubic") - -# Animate multiple properties -mcrfpy.animate(sprite, "opacity", 0.5, 500, "ease_out_quad") -mcrfpy.animate(sprite, "scale_x", 2.0, 800, "bounce_out") -``` - -**Supported Properties:** -- Position: `x`, `y`, `pos` -- Size: `w`, `h`, `size`, `scale_x`, `scale_y` -- Colors: `r`, `g`, `b`, `a`, `fill_color`, `outline_color` -- Grid-specific: `zoom`, `left_edge`, `top_edge` -- Caption-specific: `font_size` - -**Implementation:** See `src/AnimationManager.cpp::createAnimation()` - -### Easing Functions - -24+ easing functions available: - -**Families:** -- Linear -- Quad, Cubic, Quart, Quint -- Sine, Expo, Circ -- Elastic, Back, Bounce - -**Variants:** `ease_in_*`, `ease_out_*`, `ease_in_out_*` - -**Implementation:** All easing functions in `src/Animation.cpp` - -### Execution Model - -**Pure C++ Execution:** -- Animations run in C++ update loop - no Python callbacks per frame -- High performance: thousands of concurrent animations possible -- Frame-independent: adjusts for variable frame times - -**Lifecycle:** -1. Created via `mcrfpy.animate()` -2. AnimationManager updates each frame -3. Auto-destroyed on completion or target destruction -4. Weak pointer tracking prevents use-after-free - -**See:** `src/AnimationManager.cpp::update()` for frame update logic - -## Current Issues & Limitations - -**Known Issues:** -- API inconsistency: position vs frame animation differs (see [FINAL_RECOMMENDATIONS.md](../FINAL_RECOMMENDATIONS.md)) -- Property locking: Multiple animations can conflict on same property ([#120](../issues/120)) -- Rotation not yet supported ([#100](../issues/100)) - -**Recommendations from Strategic Review:** -Per FINAL_RECOMMENDATIONS.md, animation bugs contributed to tutorial burnout. Current system is feature-complete but needs: -1. API consistency audit -2. Bug fixes for known issues -3. Comprehensive testing - -## Common Tasks - -### Basic Animation - -```python -# Linear movement -mcrfpy.animate(entity, "x", 500, 2000, "linear") - -# Smooth bounce -mcrfpy.animate(frame, "y", 300, 1000, "ease_out_bounce") -``` - -### Color Fades - -```python -# Fade to red -mcrfpy.animate(caption, "r", 255, 500, "ease_in_quad") - -# Fade out -mcrfpy.animate(sprite, "a", 0, 1000, "ease_out_cubic") -``` - -### Delta Animations - -```python -# Move relative to current position -current_x = entity.x -mcrfpy.animate(entity, "x", current_x + 100, 500, "ease_in_out_quad") -``` - -### Completion Callbacks - -```python -def on_complete(runtime_ms): - print(f"Animation completed after {runtime_ms}ms") - # Trigger next action - -mcrfpy.animate(sprite, "x", 400, 1000, "linear", callback=on_complete) -``` - -**Implementation:** [#119](../issues/119) - Callbacks fire when animation completes - -## Related Systems - -- [[UI-Component-Hierarchy]] - All UIDrawable objects are animatable -- [[Grid-System]] - Grid viewport animations (zoom, pan) -- [[Performance-and-Profiling]] - Animation time tracked separately - -## Design Decisions - -**Why Property-Based?** -- Flexible: Any numeric property animatable -- Type-safe: Properties validated at C++ level -- Performant: No Python overhead during animation - -**Why Weak Pointers?** -- Prevents crashes when animated objects destroyed -- Automatic cleanup on target death -- See: `src/AnimationManager.cpp` RAII overhaul (commit e9e9cd2) - -**Tradeoffs:** -- More complex than tween libraries -- Requires property exposure in Python bindings -- API surface larger than simple position tweening - ---- - -**Historical Notes:** -- ANIMATION_FIX_IMPLEMENTATION.md documents segfault fix (race conditions resolved) -- Major refactor July 2025: Weak pointer tracking eliminated use-after-free bugs \ No newline at end of file +# Animation System + +The Animation System provides property-based animations with 30+ easing functions for smooth transitions on all UI elements. + +## Quick Reference + +**Related Issues:** +- [#120](../issues/120) - Animation Property Locking (Tier 1 - Active) +- [#119](../issues/119) - Animation Completion Callbacks (Closed - Implemented) +- [#229](../issues/229) - Animation callbacks pass (target, property, value) + +**Key Files:** +- `src/AnimationManager.h` / `src/AnimationManager.cpp` - Animation execution engine +- `src/Animation.h` - Base Animation class +- `src/UIDrawable.h` - Animatable properties defined here + +--- + +## The `.animate()` Method + +The primary way to create animations is the `.animate()` method available on all UI elements: + +```python +import mcrfpy + +frame = mcrfpy.Frame(pos=(100, 100), size=(200, 150)) + +# animate(property, target_value, duration_seconds, easing) +frame.animate("x", 500.0, 2.0, mcrfpy.Easing.EASE_IN_OUT) +frame.animate("opacity", 0.5, 1.0, mcrfpy.Easing.EASE_OUT_QUAD) +``` + +**Parameters:** +- `property` (str): Name of the property to animate +- `target_value`: End value (float, int, or Color tuple) +- `duration` (float): Duration in seconds +- `easing` (Easing): Easing function from `mcrfpy.Easing` enum +- `callback` (optional): Function called on completion + +--- + +## Animatable Properties by Type + +### Frame +| Property | Type | Notes | +|----------|------|-------| +| `x`, `y` | float | Position | +| `w`, `h` | float | Size | +| `outline` | float | Outline thickness | +| `opacity` | float | 0.0 to 1.0 | +| `fill_color` | Color | Animate as `(r, g, b, a)` tuple | +| `outline_color` | Color | Animate as `(r, g, b, a)` tuple | + +### Caption +| Property | Type | Notes | +|----------|------|-------| +| `x`, `y` | float | Position | +| `opacity` | float | 0.0 to 1.0 | +| `outline` | float | Text outline thickness | +| `fill_color` | Color | Text fill color | +| `outline_color` | Color | Text outline color | + +### Sprite +| Property | Type | Notes | +|----------|------|-------| +| `x`, `y` | float | Position | +| `scale` | float | Uniform scale factor | +| `sprite_index` | int | Sprite sheet index (truncated to int) | +| `opacity` | float | 0.0 to 1.0 | + +### Grid +| Property | Type | Notes | +|----------|------|-------| +| `x`, `y` | float | Position on screen | +| `w`, `h` | float | Viewport size | +| `center_x`, `center_y` | float | Camera pan position | +| `zoom` | float | Camera zoom level | + +### Entity (must be attached to a Grid) +| Property | Type | Notes | +|----------|------|-------| +| `x`, `y` | float | Alias for draw position | +| `draw_x`, `draw_y` | float | Visual position in tile coordinates | +| `sprite_index` | int | Sprite sheet index | +| `sprite_scale` | float | Entity sprite scale | + +--- + +## Easing Functions (`mcrfpy.Easing`) + +30+ easing functions are available: + +**Basic:** +- `Easing.LINEAR` +- `Easing.EASE_IN`, `Easing.EASE_OUT`, `Easing.EASE_IN_OUT` + +**Families** (each has `_IN`, `_OUT`, `_IN_OUT` variants): +- `QUAD` - Quadratic +- `CUBIC` - Cubic +- `QUART` - Quartic +- `SINE` - Sinusoidal +- `EXPO` - Exponential +- `CIRC` - Circular +- `ELASTIC` - Elastic spring +- `BACK` - Overshoot +- `BOUNCE` - Bouncing + +**Example:** `Easing.EASE_IN_OUT_CUBIC`, `Easing.EASE_OUT_BOUNCE`, `Easing.EASE_IN_ELASTIC` + +--- + +## Completion Callbacks + +Animation callbacks receive `(target, property, final_value)`: + +```python +def on_complete(target, prop, value): + print(f"{type(target).__name__}.{prop} reached {value}") + +frame.animate("x", 500.0, 2.0, mcrfpy.Easing.EASE_IN_OUT, callback=on_complete) +``` + +**Callback arguments:** +- `target`: The animated object (Frame, Sprite, Entity, etc.) +- `prop` (str): Property name that was animated (e.g., `"x"`, `"opacity"`) +- `value`: Final value (float, int, or `(r, g, b, a)` tuple for colors) + +### Chaining Animations + +Use callbacks to create animation sequences: + +```python +def step2(target, prop, value): + target.animate("y", 300.0, 1.0, mcrfpy.Easing.EASE_OUT_BOUNCE) + +def step1(target, prop, value): + target.animate("x", 500.0, 1.0, mcrfpy.Easing.EASE_IN_OUT, callback=step2) + +frame.animate("opacity", 1.0, 0.5, mcrfpy.Easing.EASE_IN, callback=step1) +``` + +**Note:** It is safe to start new animations from within callbacks, including animations on the same target and property. + +--- + +## Execution Model + +**Pure C++ Execution:** +- Animations run in the C++ update loop - no Python callbacks per frame +- High performance: thousands of concurrent animations +- Frame-independent: adjusts for variable frame times + +**Lifecycle:** +1. Created via `.animate()` call +2. AnimationManager updates each frame +3. Auto-destroyed on completion or target destruction +4. Weak pointer tracking prevents use-after-free + +**Conflicting Animations:** +Multiple animations on the same property will conflict. The most recently created animation takes precedence. Property locking ([#120](../issues/120)) is planned to prevent this. + +--- + +## Color Animations + +Animate colors by targeting `fill_color` or `outline_color`: + +```python +# Fade to red fill +frame.animate("fill_color", (255, 0, 0, 255), 1.0, mcrfpy.Easing.EASE_IN) + +# Animate outline to transparent +frame.animate("outline_color", (255, 255, 255, 0), 0.5, mcrfpy.Easing.LINEAR) +``` + +Color animations interpolate each channel (R, G, B, A) independently. + +--- + +## Common Patterns + +### Smooth Entity Movement + +```python +def move_entity(entity, target_x, target_y, speed=0.3): + entity.animate("x", float(target_x), speed, mcrfpy.Easing.EASE_OUT_QUAD) + entity.animate("y", float(target_y), speed, mcrfpy.Easing.EASE_OUT_QUAD) +``` + +### Fade In/Out + +```python +# Fade in +frame.opacity = 0.0 +frame.animate("opacity", 1.0, 0.5, mcrfpy.Easing.EASE_IN) + +# Fade out and remove +def remove_on_fade(target, prop, value): + # Remove from parent scene + pass # implement removal logic + +frame.animate("opacity", 0.0, 0.5, mcrfpy.Easing.EASE_OUT, callback=remove_on_fade) +``` + +### Pulse/Breathing Effect + +```python +def pulse(target, prop, value): + if value > 0.8: + target.animate("opacity", 0.3, 1.0, mcrfpy.Easing.EASE_IN_OUT_SINE, callback=pulse) + else: + target.animate("opacity", 1.0, 1.0, mcrfpy.Easing.EASE_IN_OUT_SINE, callback=pulse) + +frame.animate("opacity", 0.3, 1.0, mcrfpy.Easing.EASE_IN_OUT_SINE, callback=pulse) +``` + +### Camera Pan + +```python +grid.animate("center_x", target_x * 16.0, 0.5, mcrfpy.Easing.EASE_IN_OUT) +grid.animate("center_y", target_y * 16.0, 0.5, mcrfpy.Easing.EASE_IN_OUT) +``` + +--- + +## Animation Object (Advanced) + +The `mcrfpy.Animation` class can be used directly for more control, though `.animate()` is preferred: + +```python +anim = mcrfpy.Animation("x", 500.0, 2.0, mcrfpy.Easing.LINEAR, callback=my_callback) +anim.start(frame) +``` + +This is functionally equivalent to `frame.animate("x", 500.0, 2.0, mcrfpy.Easing.LINEAR, callback=my_callback)`. + +--- + +## Related Systems + +- [[UI-Component-Hierarchy]] - All UIDrawable objects are animatable +- [[Grid-System]] - Grid viewport animations (zoom, pan) +- [[Input-and-Events]] - Trigger animations from input callbacks +- [[Performance-and-Profiling]] - Animation time tracked separately + +--- + +*Last updated: 2026-02-07* \ No newline at end of file