parent
f3b49e44c9
commit
097a55948c
@ -13,9 +13,18 @@ current changes on git with [previous release tags][git_tag_comparison].
|
||||
|
||||
### Changed
|
||||
- [Breaking changes to timer API][914]
|
||||
- Created getters and setters rather than exposing struct members.
|
||||
- [Removed timer auto-ticking system][931]
|
||||
- Added an example of how to tick timers manually.
|
||||
- [Breaking changes to Time API][934]
|
||||
- Created getters to get `Time` state and made members private.
|
||||
- Modifying `Time`'s values directly is no longer possible outside of bevy.
|
||||
### Fixed
|
||||
|
||||
[914]: https://github.com/bevyengine/bevy/pull/914
|
||||
[931]: https://github.com/bevyengine/bevy/pull/931
|
||||
[934]: https://github.com/bevyengine/bevy/pull/934
|
||||
|
||||
|
||||
## Version 0.3.0 (2020-11-03)
|
||||
|
||||
|
@ -4,19 +4,19 @@ use bevy_utils::{Duration, Instant};
|
||||
/// Tracks elapsed time since the last update and since the App has started
|
||||
#[derive(Debug)]
|
||||
pub struct Time {
|
||||
pub delta: Duration,
|
||||
pub instant: Option<Instant>,
|
||||
pub delta_seconds_f64: f64,
|
||||
pub delta_seconds: f32,
|
||||
pub seconds_since_startup: f64,
|
||||
pub startup: Instant,
|
||||
delta: Duration,
|
||||
last_update: Option<Instant>,
|
||||
delta_seconds_f64: f64,
|
||||
delta_seconds: f32,
|
||||
seconds_since_startup: f64,
|
||||
startup: Instant,
|
||||
}
|
||||
|
||||
impl Default for Time {
|
||||
fn default() -> Time {
|
||||
Time {
|
||||
delta: Duration::from_secs(0),
|
||||
instant: None,
|
||||
last_update: None,
|
||||
startup: Instant::now(),
|
||||
delta_seconds_f64: 0.0,
|
||||
seconds_since_startup: 0.0,
|
||||
@ -28,15 +28,55 @@ impl Default for Time {
|
||||
impl Time {
|
||||
pub fn update(&mut self) {
|
||||
let now = Instant::now();
|
||||
if let Some(instant) = self.instant {
|
||||
self.delta = now - instant;
|
||||
self.update_with_instant(now);
|
||||
}
|
||||
|
||||
pub(crate) fn update_with_instant(&mut self, instant: Instant) {
|
||||
if let Some(last_update) = self.last_update {
|
||||
self.delta = instant - last_update;
|
||||
self.delta_seconds_f64 = self.delta.as_secs_f64();
|
||||
self.delta_seconds = self.delta.as_secs_f32();
|
||||
}
|
||||
|
||||
let duration_since_startup = now - self.startup;
|
||||
let duration_since_startup = instant - self.startup;
|
||||
self.seconds_since_startup = duration_since_startup.as_secs_f64();
|
||||
self.instant = Some(now);
|
||||
self.last_update = Some(instant);
|
||||
}
|
||||
|
||||
/// The delta between the current tick and last tick as a [`Duration`]
|
||||
#[inline]
|
||||
pub fn delta(&self) -> Duration {
|
||||
self.delta
|
||||
}
|
||||
|
||||
/// The delta between the current and last tick as [`f32`] seconds
|
||||
#[inline]
|
||||
pub fn delta_seconds(&self) -> f32 {
|
||||
self.delta_seconds
|
||||
}
|
||||
|
||||
/// The delta between the current and last tick as [`f64`] seconds
|
||||
#[inline]
|
||||
pub fn delta_seconds_f64(&self) -> f64 {
|
||||
self.delta_seconds_f64
|
||||
}
|
||||
|
||||
/// The time since startup in seconds
|
||||
#[inline]
|
||||
pub fn seconds_since_startup(&self) -> f64 {
|
||||
self.seconds_since_startup
|
||||
}
|
||||
|
||||
/// The [`Instant`] the app was started
|
||||
#[inline]
|
||||
pub fn startup(&self) -> Instant {
|
||||
self.startup
|
||||
}
|
||||
|
||||
/// The ['Instant'] when [`Time::update`] was last called, if it exists
|
||||
#[inline]
|
||||
pub fn last_update(&self) -> Option<Instant> {
|
||||
self.last_update
|
||||
}
|
||||
|
||||
pub fn time_since_startup(&self) -> Duration {
|
||||
@ -47,3 +87,60 @@ impl Time {
|
||||
pub(crate) fn time_system(mut time: ResMut<Time>) {
|
||||
time.update();
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Time;
|
||||
use bevy_utils::{Duration, Instant};
|
||||
|
||||
#[test]
|
||||
fn update_test() {
|
||||
let start_instant = Instant::now();
|
||||
|
||||
// Create a `Time` for testing
|
||||
let mut time = Time {
|
||||
startup: start_instant,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
// Ensure `time` was constructed correctly
|
||||
assert_eq!(time.delta(), Duration::from_secs(0));
|
||||
assert_eq!(time.last_update(), None);
|
||||
assert_eq!(time.startup(), start_instant);
|
||||
assert_eq!(time.delta_seconds_f64(), 0.0);
|
||||
assert_eq!(time.seconds_since_startup(), 0.0);
|
||||
assert_eq!(time.delta_seconds(), 0.0);
|
||||
|
||||
// Update `time` and check results
|
||||
let first_update_instant = Instant::now();
|
||||
|
||||
time.update_with_instant(first_update_instant);
|
||||
|
||||
assert_eq!(time.delta(), Duration::from_secs(0));
|
||||
assert_eq!(time.last_update(), Some(first_update_instant));
|
||||
assert_eq!(time.startup(), start_instant);
|
||||
assert_eq!(time.delta_seconds_f64(), 0.0);
|
||||
assert_eq!(
|
||||
time.seconds_since_startup(),
|
||||
(first_update_instant - start_instant).as_secs_f64()
|
||||
);
|
||||
assert_eq!(time.delta_seconds, 0.0);
|
||||
|
||||
// Update `time` again and check results
|
||||
let second_update_instant = Instant::now();
|
||||
|
||||
time.update_with_instant(second_update_instant);
|
||||
|
||||
assert_eq!(time.delta(), second_update_instant - first_update_instant);
|
||||
assert_eq!(time.last_update(), Some(second_update_instant));
|
||||
assert_eq!(time.startup(), start_instant);
|
||||
// At this point its safe to use time.delta as a valid value
|
||||
// because it's been previously verified to be correct
|
||||
assert_eq!(time.delta_seconds_f64(), time.delta().as_secs_f64());
|
||||
assert_eq!(
|
||||
time.seconds_since_startup(),
|
||||
(second_update_instant - start_instant).as_secs_f64()
|
||||
);
|
||||
assert_eq!(time.delta_seconds(), time.delta().as_secs_f32());
|
||||
}
|
||||
}
|
||||
|
@ -40,11 +40,11 @@ impl FrameTimeDiagnosticsPlugin {
|
||||
state.frame_count += 1.0;
|
||||
diagnostics.add_measurement(Self::FRAME_COUNT, state.frame_count);
|
||||
|
||||
if time.delta_seconds_f64 == 0.0 {
|
||||
if time.delta_seconds_f64() == 0.0 {
|
||||
return;
|
||||
}
|
||||
|
||||
diagnostics.add_measurement(Self::FRAME_TIME, time.delta_seconds_f64);
|
||||
diagnostics.add_measurement(Self::FRAME_TIME, time.delta_seconds_f64());
|
||||
if let Some(fps) = diagnostics
|
||||
.get(Self::FRAME_TIME)
|
||||
.and_then(|frame_time_diagnostic| {
|
||||
|
@ -66,7 +66,7 @@ impl PrintDiagnosticsPlugin {
|
||||
time: Res<Time>,
|
||||
diagnostics: Res<Diagnostics>,
|
||||
) {
|
||||
if state.timer.tick(time.delta_seconds).finished() {
|
||||
if state.timer.tick(time.delta_seconds()).finished() {
|
||||
println!("Diagnostics:");
|
||||
println!("{}", "-".repeat(93));
|
||||
if let Some(ref filter) = state.filter {
|
||||
@ -86,7 +86,7 @@ impl PrintDiagnosticsPlugin {
|
||||
time: Res<Time>,
|
||||
diagnostics: Res<Diagnostics>,
|
||||
) {
|
||||
if state.timer.tick(time.delta_seconds).finished() {
|
||||
if state.timer.tick(time.delta_seconds()).finished() {
|
||||
println!("Diagnostics (Debug):");
|
||||
println!("{}", "-".repeat(93));
|
||||
if let Some(ref filter) = state.filter {
|
||||
|
@ -217,7 +217,7 @@ fn deselect(
|
||||
|
||||
/// Applies gravity to all entities with velocity
|
||||
fn velocity_system(time: Res<Time>, mut q: Query<Mut<Velocity>>) {
|
||||
let delta = time.delta_seconds;
|
||||
let delta = time.delta_seconds();
|
||||
|
||||
for mut v in q.iter_mut() {
|
||||
v.translation += Vec3::new(0.0, GRAVITY * delta, 0.0);
|
||||
@ -274,7 +274,7 @@ fn collision_system(
|
||||
|
||||
/// Apply velocity to positions and rotations.
|
||||
fn move_system(time: Res<Time>, mut q: Query<(&Velocity, Mut<Transform>)>) {
|
||||
let delta = time.delta_seconds;
|
||||
let delta = time.delta_seconds();
|
||||
|
||||
for (v, mut t) in q.iter_mut() {
|
||||
t.translation += delta * v.translation;
|
||||
|
@ -14,7 +14,7 @@ fn animate_sprite_system(
|
||||
mut query: Query<(&mut Timer, &mut TextureAtlasSprite, &Handle<TextureAtlas>)>,
|
||||
) {
|
||||
for (mut timer, mut sprite, texture_atlas_handle) in query.iter_mut() {
|
||||
timer.tick(time.delta_seconds);
|
||||
timer.tick(time.delta_seconds());
|
||||
if timer.finished() {
|
||||
let texture_atlas = texture_atlases.get(texture_atlas_handle).unwrap();
|
||||
sprite.index = ((sprite.index as usize + 1) % texture_atlas.textures.len()) as u32;
|
||||
|
@ -17,7 +17,7 @@ struct Rotator;
|
||||
/// rotates the parent, which will result in the child also rotating
|
||||
fn rotator_system(time: Res<Time>, mut query: Query<&mut Transform, With<Rotator>>) {
|
||||
for mut transform in query.iter_mut() {
|
||||
transform.rotation *= Quat::from_rotation_x(3.0 * time.delta_seconds);
|
||||
transform.rotation *= Quat::from_rotation_x(3.0 * time.delta_seconds());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,9 +25,9 @@ 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;
|
||||
transform.translation += Vec3::new(1.0, 0.0, 0.0) * time.delta_seconds();
|
||||
material.albedo =
|
||||
Color::BLUE * Vec3::splat((3.0 * time.seconds_since_startup as f32).sin());
|
||||
Color::BLUE * Vec3::splat((3.0 * time.seconds_since_startup() as f32).sin());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@ struct Rotator;
|
||||
/// rotates the parent, which will result in the child also rotating
|
||||
fn rotator_system(time: Res<Time>, mut query: Query<&mut Transform, With<Rotator>>) {
|
||||
for mut transform in query.iter_mut() {
|
||||
transform.rotation *= Quat::from_rotation_x(3.0 * time.delta_seconds);
|
||||
transform.rotation *= Quat::from_rotation_x(3.0 * time.delta_seconds());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,7 @@ struct PrintMessageState {
|
||||
}
|
||||
|
||||
fn print_message_system(mut state: ResMut<PrintMessageState>, time: Res<Time>) {
|
||||
if state.timer.tick(time.delta_seconds).finished() {
|
||||
if state.timer.tick(time.delta_seconds()).finished() {
|
||||
println!("{}", state.message);
|
||||
}
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ fn event_trigger_system(
|
||||
mut state: ResMut<EventTriggerState>,
|
||||
mut my_events: ResMut<Events<MyEvent>>,
|
||||
) {
|
||||
if state.event_timer.tick(time.delta_seconds).finished() {
|
||||
if state.event_timer.tick(time.delta_seconds()).finished() {
|
||||
my_events.send(MyEvent {
|
||||
message: "MyEvent just happened!".to_string(),
|
||||
});
|
||||
|
@ -97,24 +97,24 @@ fn rotate(
|
||||
let angle = std::f32::consts::PI / 2.0;
|
||||
for (parent, children) in parents_query.iter_mut() {
|
||||
if let Ok(mut transform) = transform_query.get_mut(parent) {
|
||||
transform.rotate(Quat::from_rotation_z(-angle * time.delta_seconds));
|
||||
transform.rotate(Quat::from_rotation_z(-angle * time.delta_seconds()));
|
||||
}
|
||||
|
||||
// To iterate through the entities children, just treat the Children component as a Vec
|
||||
// Alternatively, you could query entities that have a Parent component
|
||||
for child in children.iter() {
|
||||
if let Ok(mut transform) = transform_query.get_mut(*child) {
|
||||
transform.rotate(Quat::from_rotation_z(angle * 2.0 * time.delta_seconds));
|
||||
transform.rotate(Quat::from_rotation_z(angle * 2.0 * time.delta_seconds()));
|
||||
}
|
||||
}
|
||||
|
||||
// To demonstrate removing children, we'll start to remove the children after a couple of seconds
|
||||
if time.seconds_since_startup >= 2.0 && children.len() == 3 {
|
||||
if time.seconds_since_startup() >= 2.0 && children.len() == 3 {
|
||||
let child = children.last().copied().unwrap();
|
||||
commands.despawn(child);
|
||||
}
|
||||
|
||||
if time.seconds_since_startup >= 4.0 {
|
||||
if time.seconds_since_startup() >= 4.0 {
|
||||
// This will remove the entity from its parent's list of children, as well as despawn
|
||||
// any children the entity has.
|
||||
commands.despawn_recursive(parent);
|
||||
|
@ -39,7 +39,7 @@ fn setup_system(commands: &mut Commands) {
|
||||
/// using bevy's `Time` resource to get the delta between each update.
|
||||
fn timer_system(time: Res<Time>, mut query: Query<&mut Timer>) {
|
||||
for mut timer in query.iter_mut() {
|
||||
if timer.tick(time.delta_seconds).just_finished() {
|
||||
if timer.tick(time.delta_seconds()).just_finished() {
|
||||
info!("Entity timer just finished")
|
||||
}
|
||||
}
|
||||
@ -48,14 +48,14 @@ fn timer_system(time: Res<Time>, mut query: Query<&mut Timer>) {
|
||||
/// This system controls ticking the timer within the countdown resource and
|
||||
/// handling its state.
|
||||
fn countdown_system(time: Res<Time>, mut countdown: ResMut<Countdown>) {
|
||||
countdown.main_timer.tick(time.delta_seconds);
|
||||
countdown.main_timer.tick(time.delta_seconds());
|
||||
|
||||
// The API encourages this kind of timer state checking (if you're only checking for one value)
|
||||
// Additionally, `finished()` would accomplish the same thing as `just_finished` due to the timer
|
||||
// being repeating, however this makes more sense visually.
|
||||
if countdown
|
||||
.percent_trigger
|
||||
.tick(time.delta_seconds)
|
||||
.tick(time.delta_seconds())
|
||||
.just_finished()
|
||||
{
|
||||
if !countdown.main_timer.finished() {
|
||||
|
@ -174,7 +174,7 @@ fn paddle_movement_system(
|
||||
|
||||
let translation = &mut transform.translation;
|
||||
// move the paddle horizontally
|
||||
translation.x += time.delta_seconds * direction * paddle.speed;
|
||||
translation.x += time.delta_seconds() * direction * paddle.speed;
|
||||
// bound the paddle within the walls
|
||||
translation.x = translation.x.min(380.0).max(-380.0);
|
||||
}
|
||||
@ -182,7 +182,7 @@ fn paddle_movement_system(
|
||||
|
||||
fn ball_movement_system(time: Res<Time>, mut ball_query: Query<(&Ball, &mut Transform)>) {
|
||||
// clamp the timestep to stop the ball from escaping when the game starts
|
||||
let delta_seconds = f32::min(0.2, time.delta_seconds);
|
||||
let delta_seconds = f32::min(0.2, time.delta_seconds());
|
||||
|
||||
for (ball, mut transform) in ball_query.iter_mut() {
|
||||
transform.translation += ball.velocity * delta_seconds;
|
||||
|
@ -84,7 +84,7 @@ fn mouse_handler(
|
||||
mut counter: ResMut<BevyCounter>,
|
||||
) {
|
||||
if mouse_button_input.pressed(MouseButton::Left) {
|
||||
let spawn_count = (BIRDS_PER_SECOND as f32 * time.delta_seconds) as u128;
|
||||
let spawn_count = (BIRDS_PER_SECOND as f32 * time.delta_seconds()) as u128;
|
||||
let bird_x = (window.width as i32 / -2) as f32 + HALF_BIRD_SIZE;
|
||||
let bird_y = (window.height / 2) as f32 - HALF_BIRD_SIZE;
|
||||
|
||||
@ -118,9 +118,9 @@ fn mouse_handler(
|
||||
|
||||
fn movement_system(time: Res<Time>, mut bird_query: Query<(&mut Bird, &mut Transform)>) {
|
||||
for (mut bird, mut transform) in bird_query.iter_mut() {
|
||||
transform.translation.x += bird.velocity.x * time.delta_seconds;
|
||||
transform.translation.y += bird.velocity.y * time.delta_seconds;
|
||||
bird.velocity.y += GRAVITY * time.delta_seconds;
|
||||
transform.translation.x += bird.velocity.x * time.delta_seconds();
|
||||
transform.translation.y += bird.velocity.y * time.delta_seconds();
|
||||
bird.velocity.y += GRAVITY * time.delta_seconds();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,7 +62,7 @@ fn atlas_render_system(
|
||||
}
|
||||
|
||||
fn text_update_system(mut state: ResMut<State>, time: Res<Time>, mut query: Query<&mut Text>) {
|
||||
if state.timer.tick(time.delta_seconds).finished() {
|
||||
if state.timer.tick(time.delta_seconds()).finished() {
|
||||
for mut text in query.iter_mut() {
|
||||
let c = rand::random::<u8>() as char;
|
||||
if !text.value.contains(c) {
|
||||
|
@ -34,7 +34,7 @@ fn counter(mut state: Local<CounterState>, time: Res<Time>) {
|
||||
"tick {} @ {:?} [Δ{}]",
|
||||
state.count,
|
||||
time.time_since_startup(),
|
||||
time.delta_seconds
|
||||
time.delta_seconds()
|
||||
);
|
||||
}
|
||||
state.count += 1;
|
||||
|
@ -22,7 +22,7 @@ fn change_title(time: Res<Time>, mut windows: ResMut<Windows>) {
|
||||
let window = windows.get_primary_mut().unwrap();
|
||||
window.set_title(format!(
|
||||
"Seconds since startup: {}",
|
||||
time.seconds_since_startup.round()
|
||||
time.seconds_since_startup().round()
|
||||
));
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user