diff --git a/Cargo.toml b/Cargo.toml index 6acd0a1364659a8da25a24aded09b6c594f93596..7c48e6b18e3f7b9e0b4fc37768fad55e1e46cd89 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,10 +25,10 @@ bevy_text = ["bevy/bevy_text", "bevy/bevy_render"] [dependencies] interpolation = "0.2" -bevy = { version = "0.9", default-features = false } +bevy = { version = "0.10", default-features = false } [dev-dependencies] -bevy-inspector-egui = "0.14" +bevy-inspector-egui = "0.18.0" [[example]] name = "menu" @@ -61,7 +61,7 @@ required-features = [ "bevy_text", "bevy/bevy_winit" ] [[example]] name = "sequence" required-features = [ "bevy/bevy_winit" ] - -[workspace] -resolver = "2" -members = [".", "benchmarks/"] +# +#[workspace] +#resolver = "2" +#members = [".", "benchmarks/"] diff --git a/src/plugin.rs b/src/plugin.rs index 79537f4872f7f35f3d0656f7b65eb85561f0d3dd..8c1c2f5b73322ea322d2ae40855ddf6a587f7397 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -38,32 +38,34 @@ use crate::{tweenable::ComponentTarget, Animator, AnimatorState, TweenCompleted} pub struct TweeningPlugin; impl Plugin for TweeningPlugin { - fn build(&self, app: &mut App) { - app.add_event::<TweenCompleted>().add_system( - component_animator_system::<Transform>.label(AnimationSystem::AnimationUpdate), - ); - - #[cfg(feature = "bevy_ui")] - app.add_system(component_animator_system::<Style>.label(AnimationSystem::AnimationUpdate)); - - #[cfg(feature = "bevy_sprite")] - app.add_system(component_animator_system::<Sprite>.label(AnimationSystem::AnimationUpdate)); - - #[cfg(all(feature = "bevy_sprite", feature = "bevy_asset"))] - app.add_system( - asset_animator_system::<ColorMaterial>.label(AnimationSystem::AnimationUpdate), - ); - - #[cfg(feature = "bevy_text")] - app.add_system(component_animator_system::<Text>.label(AnimationSystem::AnimationUpdate)); - } + fn build(&self, app: &mut App) { + app.add_event::<TweenCompleted>().add_system( + component_animator_system::<Transform>.in_set(AnimationSystem::AnimationUpdate), + ); + + #[cfg(feature = "bevy_ui")] + app.add_system(component_animator_system::<Style>.in_set(AnimationSystem::AnimationUpdate)); + + #[cfg(feature = "bevy_sprite")] + app.add_system( + component_animator_system::<Sprite>.in_set(AnimationSystem::AnimationUpdate), + ); + + #[cfg(all(feature = "bevy_sprite", feature = "bevy_asset"))] + app.add_system( + asset_animator_system::<ColorMaterial>.in_set(AnimationSystem::AnimationUpdate), + ); + + #[cfg(feature = "bevy_text")] + app.add_system(component_animator_system::<Text>.in_set(AnimationSystem::AnimationUpdate)); + } } /// Label enum for the systems relating to animations -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, SystemLabel)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, SystemSet)] pub enum AnimationSystem { - /// Ticks animations - AnimationUpdate, + /// Ticks animations + AnimationUpdate, } /// Animator system for components. @@ -71,23 +73,23 @@ pub enum AnimationSystem { /// This system extracts all components of type `T` with an `Animator<T>` /// attached to the same entity, and tick the animator to animate the component. pub fn component_animator_system<T: Component>( - time: Res<Time>, - mut query: Query<(Entity, &mut T, &mut Animator<T>)>, - events: ResMut<Events<TweenCompleted>>, + time: Res<Time>, + mut query: Query<(Entity, &mut T, &mut Animator<T>)>, + events: ResMut<Events<TweenCompleted>>, ) { - let mut events: Mut<Events<TweenCompleted>> = events.into(); - for (entity, target, mut animator) in query.iter_mut() { - if animator.state != AnimatorState::Paused { - let speed = animator.speed(); - let mut target = ComponentTarget::new(target); - animator.tweenable_mut().tick( - time.delta().mul_f32(speed), - &mut target, - entity, - &mut events, - ); - } - } + let mut events: Mut<Events<TweenCompleted>> = events.into(); + for (entity, target, mut animator) in query.iter_mut() { + if animator.state != AnimatorState::Paused { + let speed = animator.speed(); + let mut target = ComponentTarget::new(target); + animator.tweenable_mut().tick( + time.delta().mul_f32(speed), + &mut target, + entity, + &mut events, + ); + } + } } /// Animator system for assets. @@ -98,166 +100,166 @@ pub fn component_animator_system<T: Component>( /// This requires the `bevy_asset` feature (enabled by default). #[cfg(feature = "bevy_asset")] pub fn asset_animator_system<T: Asset>( - time: Res<Time>, - assets: ResMut<Assets<T>>, - mut query: Query<(Entity, &mut AssetAnimator<T>)>, - events: ResMut<Events<TweenCompleted>>, + time: Res<Time>, + assets: ResMut<Assets<T>>, + mut query: Query<(Entity, &mut AssetAnimator<T>)>, + events: ResMut<Events<TweenCompleted>>, ) { - let mut events: Mut<Events<TweenCompleted>> = events.into(); - let mut target = AssetTarget::new(assets); - for (entity, mut animator) in query.iter_mut() { - if animator.state != AnimatorState::Paused { - target.handle = animator.handle().clone(); - if !target.is_valid() { - continue; - } - let speed = animator.speed(); - animator.tweenable_mut().tick( - time.delta().mul_f32(speed), - &mut target, - entity, - &mut events, - ); - } - } + let mut events: Mut<Events<TweenCompleted>> = events.into(); + let mut target = AssetTarget::new(assets); + for (entity, mut animator) in query.iter_mut() { + if animator.state != AnimatorState::Paused { + target.handle = animator.handle().clone(); + if !target.is_valid() { + continue; + } + let speed = animator.speed(); + animator.tweenable_mut().tick( + time.delta().mul_f32(speed), + &mut target, + entity, + &mut events, + ); + } + } } #[cfg(test)] mod tests { - use bevy::prelude::{Events, IntoSystem, System, Transform, World}; - - use crate::{lens::TransformPositionLens, *}; - - /// A simple isolated test environment with a [`World`] and a single - /// [`Entity`] in it. - struct TestEnv { - world: World, - entity: Entity, - } - - impl TestEnv { - /// Create a new test environment containing a single entity with a - /// [`Transform`], and add the given animator on that same entity. - pub fn new<T: Component>(animator: T) -> Self { - let mut world = World::new(); - world.init_resource::<Events<TweenCompleted>>(); - - let mut time = Time::default(); - time.update(); - world.insert_resource(time); - - let entity = world.spawn((Transform::default(), animator)).id(); - - Self { world, entity } - } - - /// Get the test world. - pub fn world_mut(&mut self) -> &mut World { - &mut self.world - } - - /// Tick the test environment, updating the simulation time and ticking - /// the given system. - pub fn tick(&mut self, duration: Duration, system: &mut dyn System<In = (), Out = ()>) { - // Simulate time passing by updating the simulation time resource - { - let mut time = self.world.resource_mut::<Time>(); - let last_update = time.last_update().unwrap(); - time.update_with_instant(last_update + duration); - } - - // Reset world-related change detection - self.world.clear_trackers(); - assert!(!self.transform().is_changed()); - - // Tick system - system.run((), &mut self.world); - - // Update events after system ticked, in case system emitted some events - let mut events = self.world.resource_mut::<Events<TweenCompleted>>(); - events.update(); - } - - /// Get the animator for the transform. - pub fn animator(&self) -> &Animator<Transform> { - self.world - .entity(self.entity) - .get::<Animator<Transform>>() - .unwrap() - } - - /// Get the transform component. - pub fn transform(&mut self) -> Mut<Transform> { - self.world.get_mut::<Transform>(self.entity).unwrap() - } - - /// Get the emitted event count since last tick. - pub fn event_count(&self) -> usize { - let events = self.world.resource::<Events<TweenCompleted>>(); - events.get_reader().len(events) - } - } - - #[test] - fn change_detect_component() { - let tween = Tween::new( - EaseMethod::Linear, - Duration::from_secs(1), - TransformPositionLens { - start: Vec3::ZERO, - end: Vec3::ONE, - }, - ) - .with_completed_event(0); - - let mut env = TestEnv::new(Animator::new(tween)); - - // After being inserted, components are always considered changed - let transform = env.transform(); - assert!(transform.is_changed()); - - //fn nit() {} - //let mut system = IntoSystem::into_system(nit); - let mut system = IntoSystem::into_system(component_animator_system::<Transform>); - system.initialize(env.world_mut()); - - env.tick(Duration::ZERO, &mut system); - - let animator = env.animator(); - assert_eq!(animator.state, AnimatorState::Playing); - assert_eq!(animator.tweenable().times_completed(), 0); - let transform = env.transform(); - assert!(transform.is_changed()); - assert!(transform.translation.abs_diff_eq(Vec3::ZERO, 1e-5)); - - env.tick(Duration::from_millis(500), &mut system); - - assert_eq!(env.event_count(), 0); - let animator = env.animator(); - assert_eq!(animator.state, AnimatorState::Playing); - assert_eq!(animator.tweenable().times_completed(), 0); - let transform = env.transform(); - assert!(transform.is_changed()); - assert!(transform.translation.abs_diff_eq(Vec3::splat(0.5), 1e-5)); - - env.tick(Duration::from_millis(500), &mut system); - - assert_eq!(env.event_count(), 1); - let animator = env.animator(); - assert_eq!(animator.state, AnimatorState::Playing); - assert_eq!(animator.tweenable().times_completed(), 1); - let transform = env.transform(); - assert!(transform.is_changed()); - assert!(transform.translation.abs_diff_eq(Vec3::ONE, 1e-5)); - - env.tick(Duration::from_millis(100), &mut system); - - assert_eq!(env.event_count(), 0); - let animator = env.animator(); - assert_eq!(animator.state, AnimatorState::Playing); - assert_eq!(animator.tweenable().times_completed(), 1); - let transform = env.transform(); - assert!(!transform.is_changed()); - assert!(transform.translation.abs_diff_eq(Vec3::ONE, 1e-5)); - } + use bevy::prelude::{Events, IntoSystem, System, Transform, World}; + + use crate::{lens::TransformPositionLens, *}; + + /// A simple isolated test environment with a [`World`] and a single + /// [`Entity`] in it. + struct TestEnv { + world: World, + entity: Entity, + } + + impl TestEnv { + /// Create a new test environment containing a single entity with a + /// [`Transform`], and add the given animator on that same entity. + pub fn new<T: Component>(animator: T) -> Self { + let mut world = World::new(); + world.init_resource::<Events<TweenCompleted>>(); + + let mut time = Time::default(); + time.update(); + world.insert_resource(time); + + let entity = world.spawn((Transform::default(), animator)).id(); + + Self { world, entity } + } + + /// Get the test world. + pub fn world_mut(&mut self) -> &mut World { + &mut self.world + } + + /// Tick the test environment, updating the simulation time and ticking + /// the given system. + pub fn tick(&mut self, duration: Duration, system: &mut dyn System<In = (), Out = ()>) { + // Simulate time passing by updating the simulation time resource + { + let mut time = self.world.resource_mut::<Time>(); + let last_update = time.last_update().unwrap(); + time.update_with_instant(last_update + duration); + } + + // Reset world-related change detection + self.world.clear_trackers(); + assert!(!self.transform().is_changed()); + + // Tick system + system.run((), &mut self.world); + + // Update events after system ticked, in case system emitted some events + let mut events = self.world.resource_mut::<Events<TweenCompleted>>(); + events.update(); + } + + /// Get the animator for the transform. + pub fn animator(&self) -> &Animator<Transform> { + self.world + .entity(self.entity) + .get::<Animator<Transform>>() + .unwrap() + } + + /// Get the transform component. + pub fn transform(&mut self) -> Mut<Transform> { + self.world.get_mut::<Transform>(self.entity).unwrap() + } + + /// Get the emitted event count since last tick. + pub fn event_count(&self) -> usize { + let events = self.world.resource::<Events<TweenCompleted>>(); + events.get_reader().len(events) + } + } + + #[test] + fn change_detect_component() { + let tween = Tween::new( + EaseMethod::Linear, + Duration::from_secs(1), + TransformPositionLens { + start: Vec3::ZERO, + end: Vec3::ONE, + }, + ) + .with_completed_event(0); + + let mut env = TestEnv::new(Animator::new(tween)); + + // After being inserted, components are always considered changed + let transform = env.transform(); + assert!(transform.is_changed()); + + //fn nit() {} + //let mut system = IntoSystem::into_system(nit); + let mut system = IntoSystem::into_system(component_animator_system::<Transform>); + system.initialize(env.world_mut()); + + env.tick(Duration::ZERO, &mut system); + + let animator = env.animator(); + assert_eq!(animator.state, AnimatorState::Playing); + assert_eq!(animator.tweenable().times_completed(), 0); + let transform = env.transform(); + assert!(transform.is_changed()); + assert!(transform.translation.abs_diff_eq(Vec3::ZERO, 1e-5)); + + env.tick(Duration::from_millis(500), &mut system); + + assert_eq!(env.event_count(), 0); + let animator = env.animator(); + assert_eq!(animator.state, AnimatorState::Playing); + assert_eq!(animator.tweenable().times_completed(), 0); + let transform = env.transform(); + assert!(transform.is_changed()); + assert!(transform.translation.abs_diff_eq(Vec3::splat(0.5), 1e-5)); + + env.tick(Duration::from_millis(500), &mut system); + + assert_eq!(env.event_count(), 1); + let animator = env.animator(); + assert_eq!(animator.state, AnimatorState::Playing); + assert_eq!(animator.tweenable().times_completed(), 1); + let transform = env.transform(); + assert!(transform.is_changed()); + assert!(transform.translation.abs_diff_eq(Vec3::ONE, 1e-5)); + + env.tick(Duration::from_millis(100), &mut system); + + assert_eq!(env.event_count(), 0); + let animator = env.animator(); + assert_eq!(animator.state, AnimatorState::Playing); + assert_eq!(animator.tweenable().times_completed(), 1); + let transform = env.transform(); + assert!(!transform.is_changed()); + assert!(transform.translation.abs_diff_eq(Vec3::ONE, 1e-5)); + } }