pub struct TransformInterpolationPlugin {
pub interpolate_translation_all: bool,
pub interpolate_rotation_all: bool,
pub interpolate_scale_all: bool,
}
Expand description
A plugin for Transform
interpolation, making movement in FixedUpdate
appear smooth.
Transform interpolation applies easing between the old and current Transform
in between fixed timesteps. This results in movement that looks smooth and accurate,
at the cost of rendered positions being slightly behind the “true” gameplay positions.
This plugin requires the TransformEasingPlugin
to function. It is automatically added
if not already present in the app.
§Usage
Transform interpolation can be enabled for a given entity by adding the TransformInterpolation
component.
use bevy::prelude::*;
use bevy_transform_interpolation::prelude::*;
fn setup(mut commands: Commands) {
// Interpolate the entire transform: translation, rotation, and scale.
commands.spawn((
Transform::default(),
TransformInterpolation,
));
}
Now, any changes made to the Transform
of the entity in FixedPreUpdate
, FixedUpdate
,
or FixedPostUpdate
will automatically be smoothed in between fixed timesteps.
Transform properties can also be interpolated individually by adding the TranslationInterpolation
,
RotationInterpolation
, and ScaleInterpolation
components.
fn setup(mut commands: Commands) {
// Only interpolate translation.
commands.spawn((Transform::default(), TranslationInterpolation));
// Only interpolate rotation.
commands.spawn((Transform::default(), RotationInterpolation));
// Only interpolate scale.
commands.spawn((Transform::default(), ScaleInterpolation));
// Interpolate translation and rotation, but not scale.
commands.spawn((
Transform::default(),
TranslationInterpolation,
RotationInterpolation,
));
}
If you want all entities with a Transform
to be interpolated by default, you can use
TransformInterpolationPlugin::interpolate_all()
, or set the interpolate_translation_all
,
interpolate_rotation_all
, and interpolate_scale_all
fields.
fn main() {
App::new()
.add_plugins(TransformInterpolationPlugin {
// Interpolate translation and rotation by default, but not scale.
interpolate_translation_all: true,
interpolate_rotation_all: true,
interpolate_scale_all: false,
})
// ...
.run();
}
When interpolation is enabled for all entities by default, you can still opt out of it for individual entities
by adding the NoTransformEasing
component, or the individual NoTranslationEasing
, NoRotationEasing
,
and NoScaleEasing
components.
Note that changing Transform
manually in any schedule that doesn’t use a fixed timestep is also supported,
but it is equivalent to teleporting, and disables interpolation for the entity for the remainder of that fixed timestep.
§Alternatives
For games where low latency is crucial for gameplay, such as in some first-person shooters
or racing games, the small delay introduced by interpolation may be undesirable. In those cases,
one option is to use the TransformExtrapolationPlugin
instea.
Transform extrapolation predicts future positions based on velocity, and applies easing between
the current and predicted Transform
. This results in movement that looks smooth and feels responsive,
but can stutter when the prediction is incorrect, such as when velocity changes abruptly.
§Easing Backends
By default, transform interpolation uses linear interpolation (lerp
) for easing translation and scale,
and spherical linear interpolation (slerp
) for easing rotation.
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.
Fields§
§interpolate_translation_all: bool
If true
, translation will be interpolated for all entities with the Transform
component by default.
This can be overridden for individual entities by adding the NoTranslationEasing
or NoTransformEasing
component.
interpolate_rotation_all: bool
If true
, rotation will be interpolated for all entities with the Transform
component by default.
This can be overridden for individual entities by adding the NoRotationEasing
or NoTransformEasing
component.
interpolate_scale_all: bool
If true
, scale will be interpolated for all entities with the Transform
component by default.
This can be overridden for individual entities by adding the NoScaleEasing
or NoTransformEasing
component.
Implementations§
source§impl TransformInterpolationPlugin
impl TransformInterpolationPlugin
sourcepub const fn interpolate_all() -> Self
pub const fn interpolate_all() -> Self
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.
Trait Implementations§
source§impl Debug for TransformInterpolationPlugin
impl Debug for TransformInterpolationPlugin
source§impl Default for TransformInterpolationPlugin
impl Default for TransformInterpolationPlugin
source§fn default() -> TransformInterpolationPlugin
fn default() -> TransformInterpolationPlugin
source§impl Plugin for TransformInterpolationPlugin
impl Plugin for TransformInterpolationPlugin
source§fn finish(&self, app: &mut App)
fn finish(&self, app: &mut App)
App
, once all plugins registered are ready. This can
be useful for plugins that depends on another plugin asynchronous setup, like the renderer.source§fn ready(&self, _app: &App) -> bool
fn ready(&self, _app: &App) -> bool
finish
should be called.source§fn cleanup(&self, _app: &mut App)
fn cleanup(&self, _app: &mut App)
Auto Trait Implementations§
impl Freeze for TransformInterpolationPlugin
impl RefUnwindSafe for TransformInterpolationPlugin
impl Send for TransformInterpolationPlugin
impl Sync for TransformInterpolationPlugin
impl Unpin for TransformInterpolationPlugin
impl UnwindSafe for TransformInterpolationPlugin
Blanket Implementations§
source§impl<T, U> AsBindGroupShaderType<U> for T
impl<T, U> AsBindGroupShaderType<U> for T
source§fn as_bind_group_shader_type(&self, _images: &RenderAssets<GpuImage>) -> U
fn as_bind_group_shader_type(&self, _images: &RenderAssets<GpuImage>) -> U
T
ShaderType
for self
. When used in AsBindGroup
derives, it is safe to assume that all images in self
exist.source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait>
(where Trait: Downcast
) to Box<dyn Any>
. Box<dyn Any>
can
then be further downcast
into Box<ConcreteType>
where ConcreteType
implements Trait
.source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait>
(where Trait: Downcast
) to Rc<Any>
. Rc<Any>
can then be
further downcast
into Rc<ConcreteType>
where ConcreteType
implements Trait
.source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &Any
’s vtable from &Trait
’s.source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &mut Any
’s vtable from &mut Trait
’s.source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
source§impl<T> FromWorld for Twhere
T: Default,
impl<T> FromWorld for Twhere
T: Default,
source§fn from_world(_world: &mut World) -> T
fn from_world(_world: &mut World) -> T
Creates Self
using default()
.
source§impl<T> Instrument for T
impl<T> Instrument for T
source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
source§impl<T> IntoEither for T
impl<T> IntoEither for T
source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moresource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read more