use bevy::{ecs::query::QueryData, prelude::*};
use bevy_transform_interpolation::{VelocitySource, prelude::*};
#[expect(deprecated)]
pub use bevy_transform_interpolation::{
TransformEasingSet, TransformEasingSystems,
prelude::{
NoRotationEasing, NoScaleEasing, NoTransformEasing, NoTranslationEasing,
RotationExtrapolation, RotationHermiteEasing, RotationInterpolation, ScaleInterpolation,
TransformExtrapolation, TransformHermiteEasing, TransformInterpolation,
TranslationExtrapolation, TranslationHermiteEasing, TranslationInterpolation,
},
};
use crate::prelude::*;
#[cfg_attr(feature = "2d", doc = "use avian2d::prelude::*;")]
#[cfg_attr(feature = "3d", doc = "use avian3d::prelude::*;")]
#[cfg_attr(feature = "2d", doc = "# use avian2d::prelude::*;")]
#[cfg_attr(feature = "3d", doc = "# use avian3d::prelude::*;")]
#[cfg_attr(feature = "2d", doc = "# use avian2d::prelude::*;")]
#[cfg_attr(feature = "3d", doc = "# use avian3d::prelude::*;")]
#[cfg_attr(feature = "2d", doc = "# use avian2d::prelude::*;")]
#[cfg_attr(feature = "3d", doc = "# use avian3d::prelude::*;")]
#[derive(Debug, Default)]
pub struct PhysicsInterpolationPlugin {
interpolate_translation_all: bool,
interpolate_rotation_all: bool,
extrapolate_translation_all: bool,
extrapolate_rotation_all: bool,
}
impl PhysicsInterpolationPlugin {
pub const fn interpolate_all() -> Self {
Self {
interpolate_translation_all: true,
interpolate_rotation_all: true,
extrapolate_translation_all: false,
extrapolate_rotation_all: false,
}
}
pub const fn interpolate_translation_all() -> Self {
Self {
interpolate_translation_all: true,
interpolate_rotation_all: false,
extrapolate_translation_all: false,
extrapolate_rotation_all: false,
}
}
pub const fn interpolate_rotation_all() -> Self {
Self {
interpolate_translation_all: false,
interpolate_rotation_all: true,
extrapolate_translation_all: false,
extrapolate_rotation_all: false,
}
}
pub const fn extrapolate_all() -> Self {
Self {
interpolate_translation_all: false,
interpolate_rotation_all: false,
extrapolate_translation_all: true,
extrapolate_rotation_all: true,
}
}
pub const fn extrapolate_translation_all() -> Self {
Self {
interpolate_translation_all: false,
interpolate_rotation_all: false,
extrapolate_translation_all: true,
extrapolate_rotation_all: false,
}
}
pub const fn extrapolate_rotation_all() -> Self {
Self {
interpolate_translation_all: false,
interpolate_rotation_all: false,
extrapolate_translation_all: false,
extrapolate_rotation_all: true,
}
}
}
impl Plugin for PhysicsInterpolationPlugin {
fn build(&self, app: &mut App) {
app.add_plugins((
TransformInterpolationPlugin::default(),
TransformExtrapolationPlugin::<LinVelSource, AngVelSource>::default(),
TransformHermiteEasingPlugin::<LinVelSource, AngVelSource>::default(),
));
app.register_required_components::<TranslationHermiteEasing, PreviousLinearVelocity>();
app.register_required_components::<RotationHermiteEasing, PreviousAngularVelocity>();
if self.interpolate_translation_all {
let _ = app.try_register_required_components::<RigidBody, TranslationInterpolation>();
}
if self.interpolate_rotation_all {
let _ = app.try_register_required_components::<RigidBody, RotationInterpolation>();
}
if self.extrapolate_translation_all {
let _ = app.try_register_required_components::<RigidBody, TranslationExtrapolation>();
}
if self.extrapolate_rotation_all {
let _ = app.try_register_required_components::<RigidBody, RotationExtrapolation>();
}
app.add_systems(
PhysicsSchedule,
update_previous_velocity.in_set(PhysicsStepSystems::First),
);
}
}
#[derive(Component, Default, Deref, DerefMut)]
struct PreviousLinearVelocity(Vector);
#[derive(Component, Default, Deref, DerefMut)]
struct PreviousAngularVelocity(AngularVelocity);
#[derive(QueryData)]
struct LinVelSource;
impl VelocitySource for LinVelSource {
type Previous = PreviousLinearVelocity;
type Current = LinearVelocity;
fn previous(previous: &Self::Previous) -> Vec3 {
#[cfg(feature = "2d")]
{
previous.f32().extend(0.0)
}
#[cfg(feature = "3d")]
{
previous.f32()
}
}
fn current(current: &Self::Current) -> Vec3 {
#[cfg(feature = "2d")]
{
current.0.f32().extend(0.0)
}
#[cfg(feature = "3d")]
{
current.0.f32()
}
}
}
#[derive(QueryData)]
struct AngVelSource;
#[allow(clippy::unnecessary_cast)]
impl VelocitySource for AngVelSource {
type Previous = PreviousAngularVelocity;
type Current = AngularVelocity;
fn previous(previous: &Self::Previous) -> Vec3 {
#[cfg(feature = "2d")]
{
Vec3::Z * previous.0.0 as f32
}
#[cfg(feature = "3d")]
{
previous.0.f32()
}
}
fn current(current: &Self::Current) -> Vec3 {
#[cfg(feature = "2d")]
{
Vec3::Z * current.0 as f32
}
#[cfg(feature = "3d")]
{
current.0.f32()
}
}
}
fn update_previous_velocity(
mut lin_vel_query: Query<(&LinearVelocity, &mut PreviousLinearVelocity)>,
mut ang_vel_query: Query<(&AngularVelocity, &mut PreviousAngularVelocity)>,
) {
for (lin_vel, mut prev_lin_vel) in &mut lin_vel_query {
prev_lin_vel.0 = lin_vel.0;
}
for (ang_vel, mut prev_ang_vel) in &mut ang_vel_query {
prev_ang_vel.0 = *ang_vel;
}
}