Skip to content

Background fixed update #7

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
5 changes: 3 additions & 2 deletions src/extrapolation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ use bevy::prelude::*;
/// Then, add the [`TransformExtrapolationPlugin`] to the app with the velocity sources:
///
/// ```
/// use bevy::{ecs::query::QueryData, prelude::*};
/// use bevy::{ecs::query::QueryData, time::TimePlugin, prelude::*};
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those are slightly out of scope for this PR, but needed for bevy 0.15.1 due to #7.

/// use bevy_transform_interpolation::{prelude::*, VelocitySource};
/// #
/// # #[derive(Component, Default)]
Expand Down Expand Up @@ -128,6 +128,7 @@ use bevy::prelude::*;
/// let mut app = App::new();
///
/// app.add_plugins((
/// TimePlugin,
/// TransformInterpolationPlugin::default(),
/// TransformExtrapolationPlugin::<LinVelSource, AngVelSource>::default(),
/// ));
Expand Down Expand Up @@ -324,7 +325,7 @@ impl<LinVel: VelocitySource, AngVel: VelocitySource> Plugin
// Add the `TransformEasingPlugin` if it hasn't been added yet.
// It performs the actual easing based on the start and end states set by the extrapolation.
if !app.is_plugin_added::<TransformEasingPlugin>() {
app.add_plugins(TransformEasingPlugin);
app.add_plugins(TransformEasingPlugin::default());
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/hermite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ use crate::{
/// along with the [`TransformInterpolationPlugin`] and/or [`TransformExtrapolationPlugin`]:
///
/// ```
/// use bevy::{ecs::query::QueryData, prelude::*};
/// use bevy::{ecs::query::QueryData, time::TimePlugin, prelude::*};
/// use bevy_transform_interpolation::{prelude::*, VelocitySource};
/// #
/// # #[derive(Component, Default)]
Expand Down Expand Up @@ -144,6 +144,7 @@ use crate::{
/// let mut app = App::new();
///
/// app.add_plugins((
/// TimePlugin,
/// TransformInterpolationPlugin::default(),
/// TransformHermiteEasingPlugin::<LinVelSource, AngVelSource>::default(),
/// ));
Expand Down
37 changes: 29 additions & 8 deletions src/interpolation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@
use crate::{
prelude::*, RotationEasingState, ScaleEasingState, TransformEasingSet, TranslationEasingState,
};
use bevy::prelude::*;
use bevy::{
ecs::schedule::{InternedScheduleLabel, ScheduleLabel},
prelude::*,
};

/// A plugin for [`Transform`] interpolation, making movement in [`FixedUpdate`] appear smooth.
///
Expand Down Expand Up @@ -80,6 +83,7 @@ use bevy::prelude::*;
/// interpolate_translation_all: true,
/// interpolate_rotation_all: true,
/// interpolate_scale_all: false,
/// ..Default::default()
/// })
/// // ...
/// .run();
Expand Down Expand Up @@ -115,7 +119,7 @@ use bevy::prelude::*;
/// If the previous and current velocities are also available, it is possible to use [Hermite interpolation]
/// with the [`TransformHermiteEasingPlugin`] to get smoother and more accurate easing. To enable Hermite interpolation,
/// add the [`TransformHermiteEasing`] component to the entity in addition to the core interpolation components.
#[derive(Debug, Default)]
#[derive(Debug)]
pub struct TransformInterpolationPlugin {
/// If `true`, translation will be interpolated for all entities with the [`Transform`] component by default.
///
Expand All @@ -129,18 +133,36 @@ pub struct TransformInterpolationPlugin {
///
/// This can be overridden for individual entities by adding the [`NoScaleEasing`] or [`NoTransformEasing`] component.
pub interpolate_scale_all: bool,

/// The schedule which runs at the start of an executed fixed timestep, defaults to [`FixedFirst`].
pub schedule_fixed_first: InternedScheduleLabel,
/// The schedule which runs at the end of an executed fixed timestep, defaults to [`FixedLast`].
pub schedule_fixed_last: InternedScheduleLabel,
}

impl Default for TransformInterpolationPlugin {
fn default() -> Self {
Self {
interpolate_translation_all: false,
interpolate_rotation_all: false,
interpolate_scale_all: false,
schedule_fixed_first: FixedFirst.intern(),
schedule_fixed_last: FixedLast.intern(),
}
}
}

impl TransformInterpolationPlugin {
/// Enables interpolation for translation, rotation, and scale for all entities with the [`Transform`] component.
///
/// This can be overridden for individual entities by adding the [`NoTransformEasing`] component,
/// or the individual [`NoTranslationEasing`], [`NoRotationEasing`], and [`NoScaleEasing`] components.
pub const fn interpolate_all() -> Self {
pub fn interpolate_all() -> Self {
Self {
interpolate_translation_all: true,
interpolate_rotation_all: true,
interpolate_scale_all: true,
..Default::default()
}
}
}
Expand All @@ -155,7 +177,7 @@ impl Plugin for TransformInterpolationPlugin {
)>();

app.add_systems(
FixedFirst,
self.schedule_fixed_first,
(
complete_translation_easing,
complete_rotation_easing,
Expand All @@ -164,10 +186,9 @@ impl Plugin for TransformInterpolationPlugin {
.chain()
.before(TransformEasingSet::Reset),
);

// Update the start state of the interpolation at the start of the fixed timestep.
app.add_systems(
FixedFirst,
self.schedule_fixed_first,
(
update_translation_interpolation_start,
update_rotation_interpolation_start,
Expand All @@ -179,7 +200,7 @@ impl Plugin for TransformInterpolationPlugin {

// Update the end state of the interpolation at the end of the fixed timestep.
app.add_systems(
FixedLast,
self.schedule_fixed_last,
(
update_translation_interpolation_end,
update_rotation_interpolation_end,
Expand All @@ -205,7 +226,7 @@ impl Plugin for TransformInterpolationPlugin {
fn finish(&self, app: &mut App) {
// Add the `TransformEasingPlugin` if it hasn't been added yet.
if !app.is_plugin_added::<TransformEasingPlugin>() {
app.add_plugins(TransformEasingPlugin);
app.add_plugins(TransformEasingPlugin::default());
}
}
}
Expand Down
65 changes: 48 additions & 17 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,12 @@
//!
//! ```
//! # use bevy::prelude::*;
//! # use bevy::time::TimePlugin;
//! # use bevy_transform_interpolation::prelude::*;
//! #
//! fn main() {
//! App::new()
//! .add_plugins(TransformInterpolationPlugin::interpolate_all())
//! .add_plugins((TimePlugin, TransformInterpolationPlugin::interpolate_all()))
//! // ...
//! .run();
//! }
Expand Down Expand Up @@ -159,7 +160,12 @@ use extrapolation::*;
use interpolation::*;

use bevy::{
ecs::{component::Tick, query::QueryData, system::SystemChangeTick},
ecs::{
component::Tick,
query::QueryData,
schedule::{InternedScheduleLabel, InternedSystemSet, ScheduleLabel},
system::SystemChangeTick,
},
prelude::*,
};

Expand All @@ -171,8 +177,31 @@ use bevy::{
///
/// To actually perform automatic easing, an easing backend that updates the `start` and `end` states must be used.
/// The [`TransformInterpolationPlugin`] is provided for transform interpolation, but custom backends can also be implemented.
#[derive(Debug, Default)]
pub struct TransformEasingPlugin;
#[derive(Debug)]
pub struct TransformEasingPlugin {
/// The schedule which runs at the start of an executed fixed timestep, defaults to [`FixedFirst`].
pub schedule_fixed_first: InternedScheduleLabel,
/// The schedule which runs at the end of an executed fixed timestep, defaults to [`FixedLast`].
pub schedule_fixed_last: InternedScheduleLabel,
/// The schedule which runs each frame, during the fixed timestep logic, defaults to [`RunFixedMainLoop`].
pub schedule_fixed_loop: InternedScheduleLabel,
/// The schedule which runs each frame, after the fixed timestep logic, defaults to [`RunFixedMainLoopSystem::AfterFixedMainLoop`].
pub after_fixed_main_loop: InternedSystemSet,
/// If set to `true`, the plugin adds systems to update the easing values in [`TransformEasingSet::Ease`].
pub update_easing_values: bool,
}

impl Default for TransformEasingPlugin {
fn default() -> Self {
Self {
schedule_fixed_first: FixedFirst.intern(),
schedule_fixed_last: FixedLast.intern(),
schedule_fixed_loop: RunFixedMainLoop.intern(),
after_fixed_main_loop: RunFixedMainLoopSystem::AfterFixedMainLoop.intern(),
update_easing_values: true,
}
}
}

impl Plugin for TransformEasingPlugin {
fn build(&self, app: &mut App) {
Expand All @@ -190,27 +219,27 @@ impl Plugin for TransformEasingPlugin {

// Reset easing states and update start values at the start of the fixed timestep.
app.configure_sets(
FixedFirst,
self.schedule_fixed_first,
(TransformEasingSet::Reset, TransformEasingSet::UpdateStart).chain(),
);

// Update end values at the end of the fixed timestep.
app.configure_sets(FixedLast, TransformEasingSet::UpdateEnd);
app.configure_sets(self.schedule_fixed_last, TransformEasingSet::UpdateEnd);

// Perform transform easing right after the fixed timestep, before `Update`.
app.configure_sets(
RunFixedMainLoop,
self.schedule_fixed_loop,
(
TransformEasingSet::Ease,
TransformEasingSet::UpdateEasingTick,
)
.chain()
.in_set(RunFixedMainLoopSystem::AfterFixedMainLoop),
.in_set(self.after_fixed_main_loop),
);

// Reset easing states.
app.add_systems(
FixedFirst,
self.schedule_fixed_first,
(
reset_translation_easing,
reset_rotation_easing,
Expand All @@ -221,20 +250,22 @@ impl Plugin for TransformEasingPlugin {
);

app.add_systems(
RunFixedMainLoop,
self.schedule_fixed_loop,
reset_easing_states_on_transform_change.before(TransformEasingSet::Ease),
);

// Perform easing.
app.add_systems(
RunFixedMainLoop,
(ease_translation_lerp, ease_rotation_slerp, ease_scale_lerp)
.in_set(TransformEasingSet::Ease),
);
if self.update_easing_values {
// Perform easing.
app.add_systems(
self.schedule_fixed_loop,
(ease_translation_lerp, ease_rotation_slerp, ease_scale_lerp)
.in_set(TransformEasingSet::Ease),
);
}

// Update the last easing tick.
app.add_systems(
RunFixedMainLoop,
self.schedule_fixed_loop,
update_last_easing_tick.in_set(TransformEasingSet::UpdateEasingTick),
);
}
Expand Down