Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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