Skip to content
Snippets Groups Projects
Unverified Commit 454bcd00 authored by Alex Saveau's avatar Alex Saveau Committed by GitHub
Browse files

Add speed modifier (#22)

It needs to be built-in because otherwise you have to completely recreate the animation to change the speed.
parent 333c38d3
No related branches found
No related tags found
No related merge requests found
...@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ...@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add `is_forward()` and `is_backward()` convenience helpers to `TweeningDirection`. - Add `is_forward()` and `is_backward()` convenience helpers to `TweeningDirection`.
- Add `Tween::set_direction()` and `Tween::with_direction()` which allow configuring the playback direction of a tween, allowing to play it backward from end to start. - Add `Tween::set_direction()` and `Tween::with_direction()` which allow configuring the playback direction of a tween, allowing to play it backward from end to start.
- Support dynamically changing an animation's speed with `Animator::set_speed`
## [0.4.0] - 2022-04-16 ## [0.4.0] - 2022-04-16
......
use bevy::prelude::*; use bevy::prelude::*;
use bevy_inspector_egui::{Inspectable, InspectorPlugin};
use bevy_tweening::{lens::*, *}; use bevy_tweening::{lens::*, *};
fn main() -> Result<(), Box<dyn std::error::Error>> { fn main() {
App::default() App::default()
.insert_resource(WindowDescriptor { .insert_resource(WindowDescriptor {
title: "TransformRotationLens".to_string(), title: "TransformRotationLens".to_string(),
...@@ -12,10 +14,22 @@ fn main() -> Result<(), Box<dyn std::error::Error>> { ...@@ -12,10 +14,22 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
}) })
.add_plugins(DefaultPlugins) .add_plugins(DefaultPlugins)
.add_plugin(TweeningPlugin) .add_plugin(TweeningPlugin)
.add_plugin(InspectorPlugin::<Options>::new())
.add_startup_system(setup) .add_startup_system(setup)
.add_system(update_animation_speed)
.run(); .run();
}
Ok(()) #[derive(Copy, Clone, PartialEq, Inspectable)]
struct Options {
#[inspectable(min = 0.01, max = 100.)]
speed: f32,
}
impl Default for Options {
fn default() -> Self {
Self { speed: 1. }
}
} }
fn setup(mut commands: Commands) { fn setup(mut commands: Commands) {
...@@ -96,3 +110,13 @@ fn setup(mut commands: Commands) { ...@@ -96,3 +110,13 @@ fn setup(mut commands: Commands) {
} }
} }
} }
fn update_animation_speed(options: Res<Options>, mut animators: Query<&mut Animator<Transform>>) {
if !options.is_changed() {
return;
}
for mut animator in animators.iter_mut() {
animator.set_speed(options.speed);
}
}
use bevy::prelude::*; use bevy::prelude::*;
use bevy_inspector_egui::{Inspectable, InspectorPlugin};
use bevy_tweening::{lens::*, *}; use bevy_tweening::{lens::*, *};
fn main() -> Result<(), Box<dyn std::error::Error>> { fn main() {
App::default() App::default()
.insert_resource(WindowDescriptor { .insert_resource(WindowDescriptor {
title: "TransformPositionLens".to_string(), title: "TransformPositionLens".to_string(),
...@@ -12,10 +14,22 @@ fn main() -> Result<(), Box<dyn std::error::Error>> { ...@@ -12,10 +14,22 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
}) })
.add_plugins(DefaultPlugins) .add_plugins(DefaultPlugins)
.add_plugin(TweeningPlugin) .add_plugin(TweeningPlugin)
.add_plugin(InspectorPlugin::<Options>::new())
.add_startup_system(setup) .add_startup_system(setup)
.add_system(update_animation_speed)
.run(); .run();
}
Ok(()) #[derive(Copy, Clone, PartialEq, Inspectable)]
struct Options {
#[inspectable(min = 0.01, max = 100.)]
speed: f32,
}
impl Default for Options {
fn default() -> Self {
Self { speed: 1. }
}
} }
fn setup(mut commands: Commands) { fn setup(mut commands: Commands) {
...@@ -84,3 +98,13 @@ fn setup(mut commands: Commands) { ...@@ -84,3 +98,13 @@ fn setup(mut commands: Commands) {
x += size * spacing; x += size * spacing;
} }
} }
fn update_animation_speed(options: Res<Options>, mut animators: Query<&mut Animator<Transform>>) {
if !options.is_changed() {
return;
}
for mut animator in animators.iter_mut() {
animator.set_speed(options.speed);
}
}
use bevy::prelude::*; use bevy::prelude::*;
use bevy_inspector_egui::{Inspectable, InspectorPlugin};
use bevy_tweening::{lens::*, *}; use bevy_tweening::{lens::*, *};
fn main() -> Result<(), Box<dyn std::error::Error>> { fn main() {
App::default() App::default()
.insert_resource(WindowDescriptor { .insert_resource(WindowDescriptor {
title: "UiPositionLens".to_string(), title: "UiPositionLens".to_string(),
...@@ -12,10 +14,22 @@ fn main() -> Result<(), Box<dyn std::error::Error>> { ...@@ -12,10 +14,22 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
}) })
.add_plugins(DefaultPlugins) .add_plugins(DefaultPlugins)
.add_plugin(TweeningPlugin) .add_plugin(TweeningPlugin)
.add_plugin(InspectorPlugin::<Options>::new())
.add_startup_system(setup) .add_startup_system(setup)
.add_system(update_animation_speed)
.run(); .run();
}
Ok(()) #[derive(Copy, Clone, PartialEq, Inspectable)]
struct Options {
#[inspectable(min = 0.01, max = 100.)]
speed: f32,
}
impl Default for Options {
fn default() -> Self {
Self { speed: 1. }
}
} }
fn setup(mut commands: Commands) { fn setup(mut commands: Commands) {
...@@ -105,3 +119,13 @@ fn setup(mut commands: Commands) { ...@@ -105,3 +119,13 @@ fn setup(mut commands: Commands) {
x += offset_x; x += offset_x;
} }
} }
fn update_animation_speed(options: Res<Options>, mut animators: Query<&mut Animator<Style>>) {
if !options.is_changed() {
return;
}
for mut animator in animators.iter_mut() {
animator.set_speed(options.speed);
}
}
...@@ -147,6 +147,7 @@ ...@@ -147,6 +147,7 @@
//! [`Transform`]: https://docs.rs/bevy/0.7.0/bevy/transform/components/struct.Transform.html //! [`Transform`]: https://docs.rs/bevy/0.7.0/bevy/transform/components/struct.Transform.html
use bevy::{asset::Asset, prelude::*}; use bevy::{asset::Asset, prelude::*};
use std::time::Duration;
use interpolation::Ease as IEase; use interpolation::Ease as IEase;
pub use interpolation::EaseFunction; pub use interpolation::EaseFunction;
...@@ -304,6 +305,7 @@ pub struct Animator<T: Component> { ...@@ -304,6 +305,7 @@ pub struct Animator<T: Component> {
/// Control if this animation is played or not. /// Control if this animation is played or not.
pub state: AnimatorState, pub state: AnimatorState,
tweenable: Option<Box<dyn Tweenable<T> + Send + Sync + 'static>>, tweenable: Option<Box<dyn Tweenable<T> + Send + Sync + 'static>>,
speed: f32,
} }
impl<T: Component + std::fmt::Debug> std::fmt::Debug for Animator<T> { impl<T: Component + std::fmt::Debug> std::fmt::Debug for Animator<T> {
...@@ -319,6 +321,7 @@ impl<T: Component> Default for Animator<T> { ...@@ -319,6 +321,7 @@ impl<T: Component> Default for Animator<T> {
Animator { Animator {
state: Default::default(), state: Default::default(),
tweenable: None, tweenable: None,
speed: 1.,
} }
} }
} }
...@@ -338,6 +341,20 @@ impl<T: Component> Animator<T> { ...@@ -338,6 +341,20 @@ impl<T: Component> Animator<T> {
self self
} }
/// Set the initial speed of the animator. See [`Animator::set_speed`] for details.
pub fn with_speed(mut self, speed: f32) -> Self {
self.speed = speed;
self
}
/// Set the animation speed. Defaults to 1.
///
/// A speed of 2 means the animation will run twice as fast while a speed of 0.1 will result in
/// a 10x slowed animation.
pub fn set_speed(&mut self, speed: f32) {
self.speed = speed;
}
/// Set the top-level tweenable item this animator controls. /// Set the top-level tweenable item this animator controls.
pub fn set_tweenable(&mut self, tween: impl Tweenable<T> + Send + Sync + 'static) { pub fn set_tweenable(&mut self, tween: impl Tweenable<T> + Send + Sync + 'static) {
self.tweenable = Some(Box::new(tween)); self.tweenable = Some(Box::new(tween));
...@@ -395,6 +412,21 @@ impl<T: Component> Animator<T> { ...@@ -395,6 +412,21 @@ impl<T: Component> Animator<T> {
} }
} }
/// 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
}
}
/// Stop animation playback and rewind the animation. /// Stop animation playback and rewind the animation.
/// ///
/// This changes the animator state to [`AnimatorState::Paused`] and rewind its tweenable. /// This changes the animator state to [`AnimatorState::Paused`] and rewind its tweenable.
...@@ -420,6 +452,7 @@ pub struct AssetAnimator<T: Asset> { ...@@ -420,6 +452,7 @@ pub struct AssetAnimator<T: Asset> {
pub state: AnimatorState, pub state: AnimatorState,
tweenable: Option<Box<dyn Tweenable<T> + Send + Sync + 'static>>, tweenable: Option<Box<dyn Tweenable<T> + Send + Sync + 'static>>,
handle: Handle<T>, handle: Handle<T>,
speed: f32,
} }
impl<T: Asset + std::fmt::Debug> std::fmt::Debug for AssetAnimator<T> { impl<T: Asset + std::fmt::Debug> std::fmt::Debug for AssetAnimator<T> {
...@@ -436,6 +469,7 @@ impl<T: Asset> Default for AssetAnimator<T> { ...@@ -436,6 +469,7 @@ impl<T: Asset> Default for AssetAnimator<T> {
state: Default::default(), state: Default::default(),
tweenable: None, tweenable: None,
handle: Default::default(), handle: Default::default(),
speed: 1.,
} }
} }
} }
...@@ -456,6 +490,20 @@ impl<T: Asset> AssetAnimator<T> { ...@@ -456,6 +490,20 @@ impl<T: Asset> AssetAnimator<T> {
self self
} }
/// Set the initial speed of the animator. See [`Animator::set_speed`] for details.
pub fn with_speed(mut self, speed: f32) -> Self {
self.speed = speed;
self
}
/// Set the animation speed. Defaults to 1.
///
/// A speed of 2 means the animation will run twice as fast while a speed of 0.1 will result in
/// a 10x slowed animation.
pub fn set_speed(&mut self, speed: f32) {
self.speed = speed;
}
/// Set the top-level tweenable item this animator controls. /// Set the top-level tweenable item this animator controls.
pub fn set_tweenable(&mut self, tween: impl Tweenable<T> + Send + Sync + 'static) { pub fn set_tweenable(&mut self, tween: impl Tweenable<T> + Send + Sync + 'static) {
self.tweenable = Some(Box::new(tween)); self.tweenable = Some(Box::new(tween));
...@@ -513,6 +561,21 @@ impl<T: Asset> AssetAnimator<T> { ...@@ -513,6 +561,21 @@ impl<T: Asset> AssetAnimator<T> {
} }
} }
/// 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
}
}
/// Stop animation playback and rewind the animation. /// Stop animation playback and rewind the animation.
/// ///
/// This changes the animator state to [`AnimatorState::Paused`] and rewind its tweenable. /// This changes the animator state to [`AnimatorState::Paused`] and rewind its tweenable.
......
...@@ -57,9 +57,7 @@ pub fn component_animator_system<T: Component>( ...@@ -57,9 +57,7 @@ pub fn component_animator_system<T: Component>(
) { ) {
for (entity, ref mut target, ref mut animator) in query.iter_mut() { for (entity, ref mut target, ref mut animator) in query.iter_mut() {
if animator.state != AnimatorState::Paused { if animator.state != AnimatorState::Paused {
if let Some(tweenable) = animator.tweenable_mut() { animator.tick(time.delta(), target, entity, &mut event_writer);
tweenable.tick(time.delta(), target, entity, &mut event_writer);
}
} }
} }
} }
...@@ -76,9 +74,7 @@ pub fn asset_animator_system<T: Asset>( ...@@ -76,9 +74,7 @@ pub fn asset_animator_system<T: Asset>(
for (entity, ref mut animator) in query.iter_mut() { for (entity, ref mut animator) in query.iter_mut() {
if animator.state != AnimatorState::Paused { if animator.state != AnimatorState::Paused {
if let Some(target) = assets.get_mut(animator.handle()) { if let Some(target) = assets.get_mut(animator.handle()) {
if let Some(tweenable) = animator.tweenable_mut() { animator.tick(time.delta(), target, entity, &mut event_writer);
tweenable.tick(time.delta(), target, entity, &mut event_writer);
}
} }
} }
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment