From 2c9e4a2ae0d4ae972147f1505063549c30f538f3 Mon Sep 17 00:00:00 2001 From: Alex Saveau <saveau.alexandre@gmail.com> Date: Fri, 12 Aug 2022 02:17:50 -0400 Subject: [PATCH] Get rid of Optional tween (#44) --- CHANGELOG.md | 1 + examples/sequence.rs | 6 +- src/lens.rs | 3 +- src/lib.rs | 218 +++++++++---------------------------------- src/plugin.rs | 14 +-- 5 files changed, 59 insertions(+), 183 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e4d4c70..3430915 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Removed the `tweening_type` parameter from the signature of `Tween<T>::new()`; use `with_repeat_count()` and `with_repeat_strategy()` instead. +- Animators now always have a tween (instead of it being optional). This means the default animator implementation was removed. ### Removed diff --git a/examples/sequence.rs b/examples/sequence.rs index 6526df0..a4847b9 100644 --- a/examples/sequence.rs +++ b/examples/sequence.rs @@ -203,12 +203,10 @@ fn update_text( mut query_event: EventReader<TweenCompleted>, ) { let anim_red = query_anim_red.single(); - let tween_red = anim_red.tweenable().unwrap(); - let progress_red = tween_red.progress(); + let progress_red = anim_red.tweenable().progress(); let anim_blue = query_anim_blue.single(); - let tween_blue = anim_blue.tweenable().unwrap(); - let progress_blue = tween_blue.progress(); + let progress_blue = anim_blue.tweenable().progress(); let mut red_text = query_text_red.single_mut(); red_text.sections[1].value = format!("{:5.1}%", progress_red * 100.); diff --git a/src/lens.rs b/src/lens.rs index 155d07d..dbac914 100644 --- a/src/lens.rs +++ b/src/lens.rs @@ -373,9 +373,10 @@ impl Lens<Sprite> for SpriteColorLens { #[cfg(test)] mod tests { - use super::*; use std::f32::consts::TAU; + use super::*; + #[cfg(feature = "bevy_ui")] #[test] fn text_color() { diff --git a/src/lib.rs b/src/lib.rs index 551b92e..013ae84 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -151,27 +151,25 @@ //! [`Sprite`]: https://docs.rs/bevy/0.8.0/bevy/sprite/struct.Sprite.html //! [`Transform`]: https://docs.rs/bevy/0.8.0/bevy/transform/components/struct.Transform.html -use bevy::prelude::*; use std::time::Duration; #[cfg(feature = "bevy_asset")] use bevy::asset::Asset; - +use bevy::prelude::*; use interpolation::Ease as IEase; pub use interpolation::{EaseFunction, Lerp}; -pub mod lens; -mod plugin; -mod tweenable; - pub use lens::Lens; +#[cfg(feature = "bevy_asset")] +pub use plugin::asset_animator_system; pub use plugin::{component_animator_system, AnimationSystem, TweeningPlugin}; pub use tweenable::{ BoxedTweenable, Delay, Sequence, Tracks, Tween, TweenCompleted, TweenState, Tweenable, }; -#[cfg(feature = "bevy_asset")] -pub use plugin::asset_animator_system; +pub mod lens; +mod plugin; +mod tweenable; /// How many times to repeat a tween animation. See also: [`RepeatStrategy`]. #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -365,71 +363,19 @@ macro_rules! animator_impl { /// Set the top-level tweenable item this animator controls. pub fn set_tweenable(&mut self, tween: impl Tweenable<T> + Send + Sync + 'static) { - self.tweenable = Some(Box::new(tween)); + self.tweenable = Box::new(tween); } /// Get the top-level tweenable this animator is currently controlling. #[must_use] - pub fn tweenable(&self) -> Option<&(dyn Tweenable<T> + Send + Sync + 'static)> { - if let Some(tweenable) = &self.tweenable { - Some(tweenable.as_ref()) - } else { - None - } + pub fn tweenable(&self) -> &(dyn Tweenable<T> + Send + Sync + 'static) { + self.tweenable.as_ref() } /// Get the top-level mutable tweenable this animator is currently controlling. #[must_use] - pub fn tweenable_mut(&mut self) -> Option<&mut (dyn Tweenable<T> + Send + Sync + 'static)> { - if let Some(tweenable) = &mut self.tweenable { - Some(tweenable.as_mut()) - } else { - None - } - } - - /// Set the current animation playback progress. - /// - /// See [`progress()`] for details on the meaning. - /// - /// [`progress()`]: Animator::progress - pub fn set_progress(&mut self, progress: f32) { - if let Some(tweenable) = &mut self.tweenable { - tweenable.set_progress(progress) - } - } - - /// Get the current progress of the tweenable. See [`Tweenable::progress`] for - /// details. - /// - /// For sequences, the progress is measured over the entire sequence, from 0 at - /// the start of the first child tweenable to 1 at the end of the last one. - /// - /// For tracks (parallel execution), the progress is measured like a sequence - /// over the longest "path" of child tweenables. In other words, this is the - /// current elapsed time over the total tweenable duration. - #[must_use] - pub fn progress(&self) -> f32 { - if let Some(tweenable) = &self.tweenable { - tweenable.progress() - } else { - 0. - } - } - - /// Ticks the tween, if present. See [`Tweenable::tick`] for details. - pub fn tick( - &mut self, - delta: Duration, - target: &mut T, - entity: Entity, - event_writer: &mut EventWriter<TweenCompleted>, - ) -> Option<TweenState> { - if let Some(tweenable) = &mut self.tweenable { - Some(tweenable.tick(delta.mul_f32(self.speed), target, entity, event_writer)) - } else { - None - } + pub fn tweenable_mut(&mut self) -> &mut (dyn Tweenable<T> + Send + Sync + 'static) { + self.tweenable.as_mut() } /// Stop animation playback and rewind the animation. @@ -438,16 +384,7 @@ macro_rules! animator_impl { /// tweenable. pub fn stop(&mut self) { self.state = AnimatorState::Paused; - self.rewind(); - } - - /// Rewind animation playback to its initial state. - /// - /// This does not change the playback state (playing/paused). - pub fn rewind(&mut self) { - if let Some(tweenable) = &mut self.tweenable { - tweenable.rewind(); - } + self.tweenable_mut().rewind(); } }; } @@ -457,7 +394,7 @@ macro_rules! animator_impl { pub struct Animator<T: Component> { /// Control if this animation is played or not. pub state: AnimatorState, - tweenable: Option<BoxedTweenable<T>>, + tweenable: BoxedTweenable<T>, speed: f32, } @@ -469,23 +406,14 @@ impl<T: Component + std::fmt::Debug> std::fmt::Debug for Animator<T> { } } -impl<T: Component> Default for Animator<T> { - fn default() -> Self { - Self { - state: default(), - tweenable: None, - speed: 1., - } - } -} - impl<T: Component> Animator<T> { /// Create a new animator component from a single tweenable. #[must_use] pub fn new(tween: impl Tweenable<T> + Send + Sync + 'static) -> Self { Self { - tweenable: Some(Box::new(tween)), - ..default() + state: default(), + tweenable: Box::new(tween), + speed: 1., } } @@ -498,7 +426,7 @@ impl<T: Component> Animator<T> { pub struct AssetAnimator<T: Asset> { /// Control if this animation is played or not. pub state: AnimatorState, - tweenable: Option<BoxedTweenable<T>>, + tweenable: BoxedTweenable<T>, handle: Handle<T>, speed: f32, } @@ -512,27 +440,16 @@ impl<T: Asset + std::fmt::Debug> std::fmt::Debug for AssetAnimator<T> { } } -#[cfg(feature = "bevy_asset")] -impl<T: Asset> Default for AssetAnimator<T> { - fn default() -> Self { - Self { - state: default(), - tweenable: None, - handle: default(), - speed: 1., - } - } -} - #[cfg(feature = "bevy_asset")] impl<T: Asset> AssetAnimator<T> { /// Create a new asset animator component from a single tweenable. #[must_use] pub fn new(handle: Handle<T>, tween: impl Tweenable<T> + Send + Sync + 'static) -> Self { Self { - tweenable: Some(Box::new(tween)), + state: default(), + tweenable: Box::new(tween), handle, - ..default() + speed: 1., } } @@ -635,7 +552,6 @@ mod tests { assert_eq!(1., ease.sample(0.)); } - /// Animator::new() #[test] fn animator_new() { let tween = Tween::new( @@ -645,11 +561,9 @@ mod tests { ); let animator = Animator::<DummyComponent>::new(tween); assert_eq!(animator.state, AnimatorState::default()); - let tween = animator.tweenable().unwrap(); - assert_eq!(tween.progress(), 0.); + assert_eq!(animator.tweenable().progress(), 0.); } - /// Animator::with_state() #[test] fn animator_with_state() { for state in [AnimatorState::Playing, AnimatorState::Paused] { @@ -663,24 +577,6 @@ mod tests { } } - /// Animator::default() + Animator::set_tweenable() - #[test] - fn animator_default() { - let mut animator = Animator::<DummyComponent>::default(); - assert!(animator.tweenable().is_none()); - assert!(animator.tweenable_mut().is_none()); - - let tween = Tween::<DummyComponent>::new( - EaseFunction::QuadraticInOut, - Duration::from_secs(1), - DummyLens { start: 0., end: 1. }, - ); - animator.set_tweenable(tween); - assert!(animator.tweenable().is_some()); - assert!(animator.tweenable_mut().is_some()); - } - - /// Animator control playback #[test] fn animator_controls() { let tween = Tween::<DummyComponent>::new( @@ -690,35 +586,34 @@ mod tests { ); let mut animator = Animator::new(tween); assert_eq!(animator.state, AnimatorState::Playing); - assert!(animator.progress().abs() <= 1e-5); + assert!(animator.tweenable().progress().abs() <= 1e-5); animator.stop(); assert_eq!(animator.state, AnimatorState::Paused); - assert!(animator.progress().abs() <= 1e-5); + assert!(animator.tweenable().progress().abs() <= 1e-5); - animator.set_progress(0.5); + animator.tweenable_mut().set_progress(0.5); assert_eq!(animator.state, AnimatorState::Paused); - assert!((animator.progress() - 0.5).abs() <= 1e-5); + assert!((animator.tweenable().progress() - 0.5).abs() <= 1e-5); - animator.rewind(); + animator.tweenable_mut().rewind(); assert_eq!(animator.state, AnimatorState::Paused); - assert!(animator.progress().abs() <= 1e-5); + assert!(animator.tweenable().progress().abs() <= 1e-5); - animator.set_progress(0.5); + animator.tweenable_mut().set_progress(0.5); animator.state = AnimatorState::Playing; assert_eq!(animator.state, AnimatorState::Playing); - assert!((animator.progress() - 0.5).abs() <= 1e-5); + assert!((animator.tweenable().progress() - 0.5).abs() <= 1e-5); - animator.rewind(); + animator.tweenable_mut().rewind(); assert_eq!(animator.state, AnimatorState::Playing); - assert!(animator.progress().abs() <= 1e-5); + assert!(animator.tweenable().progress().abs() <= 1e-5); animator.stop(); assert_eq!(animator.state, AnimatorState::Paused); - assert!(animator.progress().abs() <= 1e-5); + assert!(animator.tweenable().progress().abs() <= 1e-5); } - /// AssetAnimator::new() #[cfg(feature = "bevy_asset")] #[test] fn asset_animator_new() { @@ -729,11 +624,11 @@ mod tests { ); let animator = AssetAnimator::new(Handle::<DummyAsset>::default(), tween); assert_eq!(animator.state, AnimatorState::default()); - let tween = animator.tweenable().unwrap(); - assert_eq!(tween.progress(), 0.); + assert_eq!(animator.handle(), Handle::<DummyAsset>::default()); + let tween = animator; + assert_eq!(tween.tweenable().progress(), 0.); } - /// AssetAnimator::with_state() #[cfg(feature = "bevy_asset")] #[test] fn asset_animator_with_state() { @@ -749,27 +644,6 @@ mod tests { } } - /// AssetAnimator::default() + AssetAnimator::set_tweenable() - #[cfg(feature = "bevy_asset")] - #[test] - fn asset_animator_default() { - let mut animator = AssetAnimator::<DummyAsset>::default(); - assert!(animator.tweenable().is_none()); - assert!(animator.tweenable_mut().is_none()); - assert_eq!(animator.handle(), Handle::<DummyAsset>::default()); - - let tween = Tween::new( - EaseFunction::QuadraticInOut, - Duration::from_secs(1), - DummyLens { start: 0., end: 1. }, - ); - animator.set_tweenable(tween); - assert!(animator.tweenable().is_some()); - assert!(animator.tweenable_mut().is_some()); - assert_eq!(animator.handle(), Handle::<DummyAsset>::default()); - } - - /// AssetAnimator control playback #[cfg(feature = "bevy_asset")] #[test] fn asset_animator_controls() { @@ -780,31 +654,31 @@ mod tests { ); let mut animator = AssetAnimator::new(Handle::<DummyAsset>::default(), tween); assert_eq!(animator.state, AnimatorState::Playing); - assert!(animator.progress().abs() <= 1e-5); + assert!(animator.tweenable().progress().abs() <= 1e-5); animator.stop(); assert_eq!(animator.state, AnimatorState::Paused); - assert!(animator.progress().abs() <= 1e-5); + assert!(animator.tweenable().progress().abs() <= 1e-5); - animator.set_progress(0.5); + animator.tweenable_mut().set_progress(0.5); assert_eq!(animator.state, AnimatorState::Paused); - assert!((animator.progress() - 0.5).abs() <= 1e-5); + assert!((animator.tweenable().progress() - 0.5).abs() <= 1e-5); - animator.rewind(); + animator.tweenable_mut().rewind(); assert_eq!(animator.state, AnimatorState::Paused); - assert!(animator.progress().abs() <= 1e-5); + assert!(animator.tweenable().progress().abs() <= 1e-5); - animator.set_progress(0.5); + animator.tweenable_mut().set_progress(0.5); animator.state = AnimatorState::Playing; assert_eq!(animator.state, AnimatorState::Playing); - assert!((animator.progress() - 0.5).abs() <= 1e-5); + assert!((animator.tweenable().progress() - 0.5).abs() <= 1e-5); - animator.rewind(); + animator.tweenable_mut().rewind(); assert_eq!(animator.state, AnimatorState::Playing); - assert!(animator.progress().abs() <= 1e-5); + assert!(animator.tweenable().progress().abs() <= 1e-5); animator.stop(); assert_eq!(animator.state, AnimatorState::Paused); - assert!(animator.progress().abs() <= 1e-5); + assert!(animator.tweenable().progress().abs() <= 1e-5); } } diff --git a/src/plugin.rs b/src/plugin.rs index c02d3f6..feb22f3 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -1,12 +1,10 @@ -use bevy::{ecs::component::Component, prelude::*}; - #[cfg(feature = "bevy_asset")] use bevy::asset::Asset; - -use crate::{Animator, AnimatorState, TweenCompleted}; +use bevy::{ecs::component::Component, prelude::*}; #[cfg(feature = "bevy_asset")] use crate::AssetAnimator; +use crate::{Animator, AnimatorState, TweenCompleted}; /// Plugin to add systems related to tweening of common components and assets. /// @@ -77,7 +75,9 @@ pub fn component_animator_system<T: Component>( ) { for (entity, ref mut target, ref mut animator) in query.iter_mut() { if animator.state != AnimatorState::Paused { - animator.tick(time.delta(), target, entity, &mut event_writer); + animator + .tweenable_mut() + .tick(time.delta(), target, entity, &mut event_writer); } } } @@ -98,7 +98,9 @@ pub fn asset_animator_system<T: Asset>( for (entity, ref mut animator) in query.iter_mut() { if animator.state != AnimatorState::Paused { if let Some(target) = assets.get_mut(&animator.handle()) { - animator.tick(time.delta(), target, entity, &mut event_writer); + animator + .tweenable_mut() + .tick(time.delta(), target, entity, &mut event_writer); } } } -- GitLab