Skip to content

Commit

Permalink
Refactor animation manager and configuration for improved type safety…
Browse files Browse the repository at this point in the history
… and performance
  • Loading branch information
wheregmis committed Jan 27, 2025
1 parent 1fe9f8b commit 50c957c
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 45 deletions.
4 changes: 2 additions & 2 deletions src/animations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ pub struct AnimationConfig {
/// Delay before animation starts
pub delay: Duration,
/// Callback when animation completes
pub on_complete: Option<OnComplete>,
pub on_complete: Option<Arc<Mutex<dyn FnMut() + Send>>>,
}

impl AnimationConfig {
Expand All @@ -84,7 +84,7 @@ impl AnimationConfig {
mode,
loop_mode: None,
delay: Duration::default(),
on_complete: None,
on_complete: None.into(),
}
}

Expand Down
78 changes: 35 additions & 43 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,19 +58,19 @@ pub mod prelude {
pub use crate::transform::Transform;
pub use crate::tween::Tween;
pub use crate::use_motion;
pub use crate::AnimationManager;
pub use crate::AnimationSequence;
pub use crate::Duration;
pub use crate::Time;
pub use crate::TimeProvider;
pub use crate::{AnimationManager, EnhancedAnimationManager};
}

pub type Time = MotionTime;

/// Animation sequence that can chain multiple animations together
pub struct AnimationSequence<T: Animatable> {
steps: Vec<AnimationStep<T>>,
current_step: usize,
current_step: u8,
on_complete: Option<Box<dyn FnOnce()>>,
}

Expand Down Expand Up @@ -192,16 +192,17 @@ impl<T: Animatable> AnimationState<T> {
fn update_spring(&mut self, spring: Spring, dt: f32) -> SpringState {
let dt = dt.min(0.064);

let force = self.target.sub(&self.current).scale(spring.stiffness);
// Cache intermediate calculations
let delta = self.target.sub(&self.current);
let force = delta.scale(spring.stiffness);
let damping = self.velocity.scale(spring.damping);
let acceleration = force.sub(&damping).scale(1.0 / spring.mass);

self.velocity = self.velocity.add(&acceleration.scale(dt));
self.current = self.current.add(&self.velocity.scale(dt));

if self.velocity.magnitude() < T::epsilon()
&& self.current.sub(&self.target).magnitude() < T::epsilon()
{
// Check completion with cached delta
if self.velocity.magnitude() < T::epsilon() && delta.magnitude() < T::epsilon() {
self.current = self.target;
SpringState::Completed
} else {
Expand Down Expand Up @@ -262,10 +263,11 @@ impl<T: Animatable> AnimationState<T> {
}
}

/// Trait for managing animations of a value
/// Combined Animation Manager trait
pub trait AnimationManager<T: Animatable>: Clone + Copy {
fn new(initial: T) -> Self;
fn animate_to(&mut self, target: T, config: AnimationConfig);
fn animate_sequence(&mut self, sequence: AnimationSequence<T>);
fn update(&mut self, dt: f32) -> bool;
fn get_value(&self) -> T;
fn is_running(&self) -> bool;
Expand All @@ -274,11 +276,6 @@ pub trait AnimationManager<T: Animatable>: Clone + Copy {
fn delay(&mut self, duration: Duration);
}

/// Enhanced AnimationManager trait with sequence capabilities
pub trait EnhancedAnimationManager<T: Animatable>: AnimationManager<T> {
fn animate_sequence(&mut self, sequence: AnimationSequence<T>);
}

#[derive(Clone, Copy)]
struct AnimationSignal<T: Animatable>(Signal<AnimationState<T>>);

Expand All @@ -291,6 +288,10 @@ impl<T: Animatable> AnimationManager<T> for AnimationSignal<T> {
self.0.write().animate_to(target, config);
}

fn animate_sequence(&mut self, _sequence: AnimationSequence<T>) {
// No-op for base AnimationSignal
}

fn update(&mut self, dt: f32) -> bool {
self.0.write().update(dt)
}
Expand All @@ -317,7 +318,7 @@ impl<T: Animatable> AnimationManager<T> for AnimationSignal<T> {
}

#[derive(Clone, Copy)]
pub struct EnhancedMotionState<T: Animatable> {
pub struct MotionState<T: Animatable> {
base: AnimationSignal<T>,
sequence: Signal<Option<SequenceState<T>>>,
}
Expand All @@ -327,7 +328,7 @@ struct SequenceState<T: Animatable> {
current_value: T,
}

impl<T: Animatable> EnhancedMotionState<T> {
impl<T: Animatable> MotionState<T> {
fn new(initial: T) -> Self {
Self {
base: AnimationSignal::new(initial),
Expand All @@ -336,35 +337,28 @@ impl<T: Animatable> EnhancedMotionState<T> {
}
}

impl<T: Animatable> EnhancedAnimationManager<T> for EnhancedMotionState<T> {
impl<T: Animatable> AnimationManager<T> for MotionState<T> {
fn new(initial: T) -> Self {
Self::new(initial)
}

fn animate_to(&mut self, target: T, config: AnimationConfig) {
self.sequence.set(None);
self.base.animate_to(target, config);
}

fn animate_sequence(&mut self, sequence: AnimationSequence<T>) {
if sequence.steps.is_empty() {
return;
}

let first_step = &sequence.steps[0];
self.base
.animate_to(first_step.target, first_step.config.clone());

self.sequence.set(Some(SequenceState {
sequence,
current_value: self.base.get_value(),
}));
}
}

impl<T: Animatable> AnimationManager<T> for EnhancedMotionState<T> {
fn new(initial: T) -> Self {
Self {
base: AnimationSignal::new(initial),
sequence: Signal::new(None),
}
}

fn animate_to(&mut self, target: T, config: AnimationConfig) {
self.sequence.set(None);
self.base.animate_to(target, config);
}

fn update(&mut self, dt: f32) -> bool {
let mut still_animating = false;
Expand All @@ -375,10 +369,10 @@ impl<T: Animatable> AnimationManager<T> for EnhancedMotionState<T> {
let total_steps = sequence_state.sequence.steps.len();

if !self.base.is_running() {
match current_step.cmp(&(total_steps - 1)) {
match current_step.cmp(&(total_steps as u8 - 1)) {
std::cmp::Ordering::Less => {
sequence_state.sequence.current_step += 1;
let step = &sequence_state.sequence.steps[current_step + 1];
let step = &sequence_state.sequence.steps[(current_step + 1) as usize];
self.base.animate_to(step.target, step.config.clone());
still_animating = true;
}
Expand Down Expand Up @@ -429,21 +423,19 @@ impl<T: Animatable> AnimationManager<T> for EnhancedMotionState<T> {
}

// Signal wrapper implementations
impl<T: Animatable> EnhancedAnimationManager<T> for Signal<EnhancedMotionState<T>> {
fn animate_sequence(&mut self, sequence: AnimationSequence<T>) {
self.write().animate_sequence(sequence);
}
}

impl<T: Animatable> AnimationManager<T> for Signal<EnhancedMotionState<T>> {
impl<T: Animatable> AnimationManager<T> for Signal<MotionState<T>> {
fn new(initial: T) -> Self {
Signal::new(EnhancedMotionState::new(initial))
Signal::new(MotionState::new(initial))
}

fn animate_to(&mut self, target: T, config: AnimationConfig) {
self.write().animate_to(target, config);
}

fn animate_sequence(&mut self, sequence: AnimationSequence<T>) {
self.write().animate_sequence(sequence);
}

fn update(&mut self, dt: f32) -> bool {
self.write().update(dt)
}
Expand All @@ -469,8 +461,8 @@ impl<T: Animatable> AnimationManager<T> for Signal<EnhancedMotionState<T>> {
}
}

pub fn use_motion<T: Animatable>(initial: T) -> impl EnhancedAnimationManager<T> {
let mut state = use_signal(|| EnhancedMotionState::new(initial));
pub fn use_motion<T: Animatable>(initial: T) -> impl AnimationManager<T> {
let mut state = use_signal(|| MotionState::new(initial));

use_future(move || async move {
let mut last_frame = Time::now();
Expand Down

0 comments on commit 50c957c

Please sign in to comment.