Skip to content

Commit

Permalink
fix errors, make cargo happy, and stop time paradoxes
Browse files Browse the repository at this point in the history
div_duration not stable, whoops
I'm sorry, but we can't go back in time,
  • Loading branch information
maniwani committed Oct 21, 2021
1 parent e30cfdb commit 754d57f
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 83 deletions.
2 changes: 1 addition & 1 deletion crates/bevy_core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub use time::*;
pub mod prelude {
#[doc(hidden)]
pub use crate::{
DefaultTaskPoolOptions, EntityLabels, FixedTimestep, Labels, Name, Time, Timer
DefaultTaskPoolOptions, EntityLabels, FixedTimestep, Labels, Name, Time, Timer,
};
}

Expand Down
34 changes: 12 additions & 22 deletions crates/bevy_core/src/time/fixed_timestep.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
use bevy_ecs::{
schedule::ShouldRun,
system::{Res, ResMut}
};
use bevy_utils::Duration;
use bevy_ecs::{schedule::ShouldRun, system::ResMut};

use crate::Time;
use bevy_utils::Duration;

#[derive(Debug, Clone)]
pub struct TimeAccumulator {
Expand All @@ -14,19 +10,16 @@ pub struct TimeAccumulator {

impl Default for TimeAccumulator {
fn default() -> Self {
Self {
time: Duration::from_secs(0),
steps: 0
Self {
time: Duration::from_secs(0),
steps: 0,
}
}
}

impl TimeAccumulator {
pub fn new(time: Duration, steps: usize) -> Self {
Self {
time,
steps
}
Self { time, steps }
}

/// The number of accrued steps.
Expand All @@ -43,14 +36,14 @@ impl TimeAccumulator {

/// The amount of time accrued toward the next step as [`f32`] % of timestep.
pub fn overstep_percentage(&self, timestep: Duration) -> f32 {
self.time.div_duration_f32(timestep)
self.time.as_secs_f32() / timestep.as_secs_f32()
}

/// The amount of time accrued toward the next step as [`f64`] % of timestep.
pub fn overstep_percentage_f64(&self, timestep: Duration) -> f64 {
self.time.div_duration_f64(timestep)
self.time.as_secs_f64() / timestep.as_secs_f64()
}

/// Add to the stored time, then convert into as many steps as possible.
pub fn add_time(&mut self, time: Duration, timestep: Duration) {
self.time += time;
Expand All @@ -74,22 +67,19 @@ impl TimeAccumulator {
}

pub fn reset(&mut self) {
self.time = 0.0;
self.time = Duration::from_secs(0);
self.steps = 0;
}
}


pub struct FixedTimestep;

impl FixedTimestep {
pub fn step (
mut accumulator: ResMut<TimeAccumulator>
) -> ShouldRun {
pub fn step(mut accumulator: ResMut<TimeAccumulator>) -> ShouldRun {
if let Some(_) = accumulator.sub_step() {
ShouldRun::YesAndCheckAgain
} else {
ShouldRun::No
}
}
}
}
55 changes: 38 additions & 17 deletions crates/bevy_core/src/time/time.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use bevy_ecs::system::ResMut;
use bevy_utils::{Duration, Instant};

use bevy_ecs::system::ResMut;
use bevy_utils::{Duration, Instant};
use crate::TimeAccumulator;

/// Tracks time elapsed since the previous update and total frame time since the app was started.
#[derive(Debug, Clone)]
Expand Down Expand Up @@ -94,8 +93,8 @@ impl Time {
pub fn fixed_delta_seconds_f64(&self) -> f64 {
self.fixed_delta_seconds_f64
}
/// Changes fixed delta. Users are strongly cautioned against modifying

/// Changes fixed delta. Users are strongly cautioned against modifying
/// the step rate this way, except during startup.
/// Prefer [`Time::set_speed_multiplier`] to ensure consistent simulation behavior.
pub fn set_steps_per_second(&mut self, steps: f32) {
Expand All @@ -121,6 +120,7 @@ impl Time {
/// Set rate app time advances relative to true clock time.
#[inline]
pub fn set_speed_multiplier(&mut self, speed_multiplier: f32) {
assert!(speed_multiplier > 0.0);
self.speed_multiplier = speed_multiplier;
}

Expand Down Expand Up @@ -172,12 +172,12 @@ impl Time {
}
}

pub(crate) fn time_system(
mut time: ResMut<Time>,
mut accumulator: ResMut<TimeAccumulator>
) {
pub(crate) fn time_system(mut time: ResMut<Time>, mut accumulator: ResMut<TimeAccumulator>) {
time.update();
accumulator.add_time(time.delta().mul_f64(time.speed_multiplier_f64()), time.fixed_delta());
accumulator.add_time(
time.delta().mul_f64(time.speed_multiplier_f64()),
time.fixed_delta(),
);
}

#[cfg(test)]
Expand All @@ -204,7 +204,10 @@ mod tests {
// Fixed delta is fixed.
assert_eq!(time.fixed_delta(), Duration::from_secs_f32(1.0 / 64.0));
assert_eq!(time.fixed_delta_seconds(), time.fixed_delta().as_secs_f32());
assert_eq!(time.fixed_delta_seconds_f64(), time.fixed_delta().as_secs_f64());
assert_eq!(
time.fixed_delta_seconds_f64(),
time.fixed_delta().as_secs_f64()
);

// Sanity check.
assert_eq!(time.last_update(), None);
Expand All @@ -226,15 +229,21 @@ mod tests {
// Fixed delta is still fixed.
assert_eq!(time.fixed_delta(), Duration::from_secs_f32(1.0 / 64.0));
assert_eq!(time.fixed_delta_seconds(), time.fixed_delta().as_secs_f32());
assert_eq!(time.fixed_delta_seconds_f64(), time.fixed_delta().as_secs_f64());
assert_eq!(
time.fixed_delta_seconds_f64(),
time.fixed_delta().as_secs_f64()
);

// Sanity check.
assert_eq!(time.last_update(), Some(first_update_instant));
assert_eq!(time.startup(), start_instant);

// App advances 1:1 to with real time.
assert_eq!(time.speed_multiplier(), 1.0);
assert_eq!(time.time_since_startup(), first_update_instant - start_instant);
assert_eq!(
time.time_since_startup(),
first_update_instant - start_instant
);

// Update `time` again and check results
let second_update_instant = Instant::now();
Expand All @@ -249,19 +258,25 @@ mod tests {
// Fixed delta is STILL fixed.
assert_eq!(time.fixed_delta(), Duration::from_secs_f32(1.0 / 64.0));
assert_eq!(time.fixed_delta_seconds(), time.fixed_delta().as_secs_f32());
assert_eq!(time.fixed_delta_seconds_f64(), time.fixed_delta().as_secs_f64());
assert_eq!(
time.fixed_delta_seconds_f64(),
time.fixed_delta().as_secs_f64()
);

// Sanity check.
assert_eq!(time.last_update(), Some(second_update_instant));
assert_eq!(time.startup(), start_instant);

// App advances 1:1 to with real time.
assert_eq!(time.speed_multiplier(), 1.0);
assert_eq!(time.time_since_startup(), second_update_instant - start_instant);
assert_eq!(
time.time_since_startup(),
second_update_instant - start_instant
);

// Make app time advance at 2x the rate of real world time.
time.set_speed_multiplier(2.0);

// Update `time` again 1 second later.
let third_update_instant = second_update_instant + Duration::from_secs(1);

Expand All @@ -274,14 +289,20 @@ mod tests {
// Fixed delta is still fixed.
assert_eq!(time.fixed_delta(), Duration::from_secs_f32(1.0 / 64.0));
assert_eq!(time.fixed_delta_seconds(), time.fixed_delta().as_secs_f32());
assert_eq!(time.fixed_delta_seconds_f64(), time.fixed_delta().as_secs_f64());
assert_eq!(
time.fixed_delta_seconds_f64(),
time.fixed_delta().as_secs_f64()
);

// Sanity check.
assert_eq!(time.last_update(), Some(third_update_instant));
assert_eq!(time.startup(), start_instant);

// App is advancing at 2x speed, so app time should have advanced by 2 seconds.
assert_eq!(time.speed_multiplier(), 2.0);
assert_eq!(time.time_since_startup(), second_update_instant - start_instant + Duration::from_secs(2));
assert_eq!(
time.time_since_startup(),
second_update_instant - start_instant + Duration::from_secs(2)
);
}
}
3 changes: 1 addition & 2 deletions examples/3d/spawner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@ fn move_cubes(
for (mut transform, material_handle) in query.iter_mut() {
let material = materials.get_mut(material_handle).unwrap();
transform.translation += Vec3::new(1.0, 0.0, 0.0) * time.delta_seconds();
material.base_color =
Color::BLUE * Vec3::splat((3.0 * time.seconds_since_startup()).sin());
material.base_color = Color::BLUE * Vec3::splat((3.0 * time.seconds_since_startup()).sin());
}
}

Expand Down
37 changes: 20 additions & 17 deletions examples/ecs/fixed_timestep.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,28 +23,31 @@ fn main() {
.run();
}

fn set_fixed_timestep(
mut time: ResMut<Time>,
) {
time.set_steps_per_second(10);
fn set_fixed_timestep(mut time: ResMut<Time>) {
time.set_steps_per_second(10.0);
}

fn frame_update(
mut last_time: Local<f32>,
time: Res<Time>,
) {
info!("time since last frame_update: {}", time.seconds_since_startup() - *last_time);
fn frame_update(mut last_time: Local<f32>, time: Res<Time>) {
info!(
"time since last frame_update: {}",
time.seconds_since_startup() - *last_time
);
*last_time = time.seconds_since_startup();
}

fn fixed_update(
mut last_time: Local<f32>,
time: Res<Time>,
accumulator: Res<TimeAccumulator>,
) {
info!("time since last fixed_update: {}\n", time.seconds_since_startup() - *last_time);
fn fixed_update(mut last_time: Local<f32>, time: Res<Time>, accumulator: Res<TimeAccumulator>) {
info!(
"time since last fixed_update: {}\n",
time.seconds_since_startup() - *last_time
);
info!("fixed timestep: {}\n", time.fixed_delta_seconds());
info!("time accrued toward fixed_update: {}\n", accumulator.time());
info!("time accrued toward fixed_update (% of time.fixed_delta): {}", accumulator.overstep_percentage());
info!(
"time accrued toward next fixed_update: {}\n",
accumulator.overstep()
);
info!(
"time accrued toward next fixed_update (% of time.fixed_delta): {}",
accumulator.overstep_percentage(time.fixed_delta())
);
*last_time = time.seconds_since_startup();
}
35 changes: 15 additions & 20 deletions examples/ecs/iter_combinations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,22 @@ struct FixedUpdateStage;

fn main() {
App::new()
.insert_resource(Msaa { samples: 4 })
.add_plugins(DefaultPlugins)
.add_startup_system(set_fixed_timestep)
.add_startup_system(generate_bodies)
.add_stage_after(
CoreStage::Update,
FixedUpdateStage,
SystemStage::parallel()
.with_run_criteria(FixedTimestep::step)
.with_system(interact_bodies)
.with_system(integrate),
)
.run();
.insert_resource(Msaa { samples: 4 })
.add_plugins(DefaultPlugins)
.add_startup_system(set_fixed_timestep)
.add_startup_system(generate_bodies)
.add_stage_after(
CoreStage::Update,
FixedUpdateStage,
SystemStage::parallel()
.with_run_criteria(FixedTimestep::step)
.with_system(interact_bodies)
.with_system(integrate),
)
.run();
}

fn set_fixed_timestep(
mut time: ResMut<Time>,
) {
fn set_fixed_timestep(mut time: ResMut<Time>) {
time.set_steps_per_second(100);
}

Expand Down Expand Up @@ -149,10 +147,7 @@ fn interact_bodies(mut query: Query<(&Mass, &GlobalTransform, &mut Acceleration)
}
}

fn integrate(
time: Res<Time>,
mut query: Query<(&mut Acceleration, &mut Transform, &mut LastPos)>
) {
fn integrate(time: Res<Time>, mut query: Query<(&mut Acceleration, &mut Transform, &mut LastPos)>) {
let dt_sq = time.fixed_delta_seconds() * time.fixed_delta_seconds();
for (mut acceleration, mut transform, mut last_pos) in query.iter_mut() {
// verlet integration
Expand Down
6 changes: 2 additions & 4 deletions examples/game/alien_cake_addict.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,8 @@ struct Game {
camera_is_focus: Vec3,
}

fn set_fixed_timestep(
mut time: ResMut<Time>,
) {
time.set_steps_per_second(1 / 5.0);
fn set_fixed_timestep(mut time: ResMut<Time>) {
time.set_steps_per_second(0.2);
}

const BOARD_SIZE_I: usize = 14;
Expand Down

0 comments on commit 754d57f

Please sign in to comment.