use std::time::Duration;
use bevy_replicon::client::confirm_history::ConfirmHistory;
use bevy_replicon::prelude::RepliconTick;
use web_time::Instant;
use crate::prelude::*;
use crate::shared::plugins::TICK_RATE;
const MAX_INTERPOLATION_DURATION: Duration = Duration::from_millis(500);
#[derive(Component)]
pub struct TransformInterpolation {
start: Transform,
end: Transform,
end_tick: RepliconTick,
duration: Duration,
end_received_at: Instant,
}
impl TransformInterpolation {
pub fn new(transform: Transform, tick: RepliconTick) -> Self {
Self {
start: transform,
end: transform,
end_tick: tick,
duration: Duration::ZERO,
end_received_at: Instant::now(),
}
}
}
pub fn transform_interpolation_plugin(app: &mut App) {
app.add_systems(Update, (record_transform_changes, apply_transform_interpolation).chain());
}
// must run before `apply_transform_interpolation`
fn record_transform_changes(
mut entities: Query<(&Transform, &ConfirmHistory, &mut TransformInterpolation), Changed<Transform>>,
) {
let now = Instant::now();
for (transform, confirm_history, mut interpolation) in &mut entities {
let tick = confirm_history.last_tick();
let tick_delta = tick - interpolation.end_tick;
let duration = Duration::from_secs_f64(tick_delta as f64 / TICK_RATE).min(MAX_INTERPOLATION_DURATION);
interpolation.start = interpolation.end;
interpolation.end = *transform;
interpolation.end_tick = tick;
interpolation.duration = duration;
interpolation.end_received_at = now;
}
}
fn apply_transform_interpolation(mut entities: Query<(&mut Transform, &TransformInterpolation)>) {
let now = Instant::now();
for (mut transform, interpolation) in &mut entities {
let t = if interpolation.duration > Duration::ZERO {
(now.duration_since(interpolation.end_received_at).as_secs_f64() / interpolation.duration.as_secs_f64())
.clamp(0.0, 1.0) as f32
} else {
1.0
};
*transform.bypass_change_detection() = Transform {
translation: interpolation.start.translation.lerp(interpolation.end.translation, t),
rotation: interpolation.start.rotation.slerp(interpolation.end.rotation, t),
scale: interpolation.start.scale.lerp(interpolation.end.scale, t),
};
}
}