Skip to content
Draft
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions crates/bevy_time/src/fixed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::{time::Time, virt::Virtual};
///
/// A specialization of the [`Time`] structure. **For method documentation, see
/// [`Time<Fixed>#impl-Time<Fixed>`].**
///
///
/// It is automatically inserted as a resource by
/// [`TimePlugin`](crate::TimePlugin) and updated based on
/// [`Time<Virtual>`](Virtual). The fixed clock is automatically set as the
Expand Down Expand Up @@ -243,12 +243,12 @@ pub fn run_fixed_main_schedule(world: &mut World) {
// Run the schedule until we run out of accumulated time
let _ = world.try_schedule_scope(FixedMain, |world, schedule| {
while world.resource_mut::<Time<Fixed>>().expend() {
*world.resource_mut::<Time>() = world.resource::<Time<Fixed>>().as_generic();
*world.resource_mut::<Time>() = world.resource::<Time<Fixed>>().as_other();
schedule.run(world);
}
});

*world.resource_mut::<Time>() = world.resource::<Time<Virtual>>().as_generic();
*world.resource_mut::<Time>() = world.resource::<Time<Virtual>>().as_other();
}

#[cfg(test)]
Expand Down
29 changes: 26 additions & 3 deletions crates/bevy_time/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,16 @@ pub mod common_conditions;
mod fixed;
mod real;
mod stopwatch;
mod strange_times;
mod time;
mod timer;
mod virt;

pub use fixed::*;
pub use real::*;
pub use stopwatch::*;
pub use time::*;
pub use strange_times::*;
pub use time::{Time, TimeDuration, TimeDurationPrecompute};
pub use timer::*;
pub use virt::*;

Expand Down Expand Up @@ -71,19 +73,27 @@ impl Plugin for TimePlugin {
.init_resource::<Time<Real>>()
.init_resource::<Time<Virtual>>()
.init_resource::<Time<Fixed>>()
.init_resource::<Time<TimeTravel>>()
.init_resource::<Time<Stepped, u32>>()
.init_resource::<Time<SteppedVirtual, u32>>()
.init_resource::<Time<SteppedTimeTravel, u32>>()
.init_resource::<TimeUpdateStrategy>();

#[cfg(feature = "bevy_reflect")]
{
app.register_type::<Time>()
.register_type::<Time<Real>>()
.register_type::<Time<Virtual>>()
.register_type::<Time<Fixed>>();
.register_type::<Time<Fixed>>()
.register_type::<Time<TimeTravel>>()
.register_type::<Time<Stepped, u32>>()
.register_type::<Time<SteppedVirtual, u32>>()
.register_type::<Time<SteppedTimeTravel, u32>>();
}

app.add_systems(
First,
time_system
(time_system, stepped_time_system)
.in_set(TimeSystems)
.ambiguous_with(message_update_system),
)
Expand Down Expand Up @@ -145,6 +155,7 @@ pub fn time_system(
mut real_time: ResMut<Time<Real>>,
mut virtual_time: ResMut<Time<Virtual>>,
mut time: ResMut<Time>,
mut time_travel: ResMut<Time<TimeTravel>>,
update_strategy: Res<TimeUpdateStrategy>,
#[cfg(feature = "std")] time_recv: Option<Res<TimeReceiver>>,
#[cfg(feature = "std")] mut has_received_time: Local<bool>,
Expand Down Expand Up @@ -178,6 +189,18 @@ pub fn time_system(
}

update_virtual_time(&mut time, &mut virtual_time, &real_time);
time_travel.advance_by(time.delta);
}

/// The system used to update the [`Time`] over stepped contexts.
pub fn stepped_time_system(
mut virtual_time: ResMut<Time<SteppedVirtual, u32>>,
mut time: ResMut<Time<Stepped, u32>>,
mut time_travel: ResMut<Time<SteppedTimeTravel, u32>>,
) {
virtual_time.advance_with_step_count(1);
*time = virtual_time.as_other();
time_travel.advance_by(time.delta);
}

#[cfg(test)]
Expand Down
151 changes: 151 additions & 0 deletions crates/bevy_time/src/strange_times.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
use core::time::Duration;

#[cfg(feature = "bevy_reflect")]
use bevy_reflect::Reflect;

use crate::{Time, TimeDuration, TimeDurationPrecompute};

/// Stepped time, augmented by 1 every frame
#[derive(Debug, Copy, Clone, Default)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Clone))]
pub struct Stepped;

/// Stepped time, augmented by a relative speed every frame
#[derive(Debug, Copy, Clone, Default)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Clone))]
pub struct SteppedVirtual {
paused: bool,
relative_speed: u32,
effective_speed: u32,
}

impl TimeDuration for u32 {
type Precompute = ();

const ZERO: Self = 0;

const DEFAULT_WRAP_PERIOD: Self = u32::MAX;

fn wrap(value: Self, wrap_period: Self) -> Self {
value % wrap_period
}
}

impl Time<SteppedVirtual, u32> {
/// Returns the speed the clock advances relative to the number of frames.
#[inline]
pub fn relative_speed(&self) -> u32 {
self.context().relative_speed
}

/// Returns the speed the clock advanced relative to the number of frames in
/// this update.
///
/// Returns `0` if the game was paused or what the `relative_speed` value
/// was at the start of this update.
#[inline]
pub fn effective_speed(&self) -> u32 {
self.context().effective_speed
}

/// Sets the speed the clock advances relative to the number of frames.
///
/// For example, setting this to `2` will make the clock advance twice as fast as the
/// number of frames.
#[inline]
pub fn set_relative_speed(&mut self, ratio: u32) {
self.context_mut().relative_speed = ratio;
}

/// Stops the clock, preventing it from advancing until resumed.
#[inline]
pub fn pause(&mut self) {
self.context_mut().paused = true;
}

/// Resumes the clock if paused.
#[inline]
pub fn unpause(&mut self) {
self.context_mut().paused = false;
}

/// Returns `true` if the clock is currently paused.
#[inline]
pub fn is_paused(&self) -> bool {
self.context().paused
}

/// Returns `true` if the clock was paused at the start of this update.
#[inline]
pub fn was_paused(&self) -> bool {
self.context().effective_speed == 0
}

pub(crate) fn advance_with_step_count(&mut self, step_count: u32) {
let effective_speed = if self.context().paused {
0
} else {
self.context().relative_speed
};
let delta = step_count * effective_speed;
self.context_mut().effective_speed = effective_speed;
self.advance_by(delta);
}
}

/// Stepped time that can go back.
#[derive(Debug, Copy, Clone, Default)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Clone))]
pub struct SteppedTimeTravel;

impl Time<SteppedTimeTravel, u32> {
/// Set the time to a specific value.
pub fn set_to(&mut self, target: u32) {
if target > self.elapsed {
self.advance_by(target - self.elapsed);
} else {
assert!(
self.elapsed > target,
"tried to move time backwards to before the start"
);
self.recede_by(self.elapsed - target);
}
}

/// Recede the time by a specific amount.
pub fn recede_by(&mut self, delta: u32) {
self.delta = delta;
self.elapsed -= delta;
self.elapsed_wrapped = u32::wrap(self.elapsed, self.wrap_period);
}
}

/// Time that can go back.
#[derive(Debug, Copy, Clone, Default)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Clone))]
pub struct TimeTravel;

impl Time<TimeTravel, Duration> {
/// Set the time to a specific duration.
pub fn set_to(&mut self, target: Duration) {
if self.elapsed >= target {
self.advance_by(target - self.elapsed);
} else {
assert!(
self.elapsed > target,
"tried to move time backwards to before the start"
);
self.recede_by(self.elapsed - target);
}
}

/// Recede the time by a specific amount.
pub fn recede_by(&mut self, delta: Duration) {
self.delta = delta;
self.precompute.update_delta(self.delta);
self.elapsed -= delta;
self.precompute.update_elapsed(self.elapsed);
self.elapsed_wrapped = Duration::wrap(self.elapsed, self.wrap_period);
self.precompute.update_elapsed_wrapped(self.elapsed_wrapped);
}
}
Loading