leafwing_input_manager/
timing.rsuse bevy::{
reflect::Reflect,
utils::{Duration, Instant},
};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize, Reflect)]
pub struct Timing {
#[serde(skip)]
pub instant_started: Option<Instant>,
pub current_duration: Duration,
pub previous_duration: Duration,
}
impl Timing {
pub const NEW: Timing = Timing {
instant_started: None,
current_duration: Duration::ZERO,
previous_duration: Duration::ZERO,
};
}
impl PartialOrd for Timing {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.current_duration.partial_cmp(&other.current_duration)
}
}
impl Timing {
pub fn tick(&mut self, current_instant: Instant, previous_instant: Instant) {
if let Some(instant_started) = self.instant_started {
self.current_duration = current_instant - instant_started;
} else {
self.current_duration = current_instant - previous_instant;
self.instant_started = Some(previous_instant);
}
}
pub fn flip(&mut self) {
self.previous_duration = self.current_duration;
self.current_duration = Duration::ZERO;
self.instant_started = None;
}
}
#[cfg(test)]
mod tests {
use crate as leafwing_input_manager;
use bevy::prelude::Reflect;
use leafwing_input_manager_macros::Actionlike;
#[derive(Actionlike, Clone, Copy, PartialEq, Eq, Hash, Debug, Reflect)]
enum Action {
Run,
Jump,
Hide,
}
#[test]
fn time_tick_ticks_away() {
use crate::action_state::ActionState;
use bevy::utils::{Duration, Instant};
let mut action_state = ActionState::<Action>::default();
assert!(action_state.released(&Action::Run));
assert!(!action_state.just_released(&Action::Jump));
action_state.tick(Instant::now(), Instant::now() - Duration::from_micros(1));
assert!(action_state.released(&Action::Jump));
assert!(!action_state.just_released(&Action::Jump));
action_state.press(&Action::Jump);
assert!(action_state.just_pressed(&Action::Jump));
action_state.tick(Instant::now(), Instant::now() - Duration::from_micros(1));
assert!(action_state.pressed(&Action::Jump));
assert!(!action_state.just_pressed(&Action::Jump));
}
#[test]
fn durations() {
use crate::action_state::ActionState;
use bevy::utils::{Duration, Instant};
let mut action_state = ActionState::<Action>::default();
assert!(action_state.released(&Action::Jump));
assert_eq!(action_state.instant_started(&Action::Jump), None,);
assert_eq!(action_state.current_duration(&Action::Jump), Duration::ZERO);
assert_eq!(
action_state.previous_duration(&Action::Jump),
Duration::ZERO
);
action_state.press(&Action::Jump);
assert!(action_state.pressed(&Action::Jump));
assert_eq!(action_state.instant_started(&Action::Jump), None);
assert_eq!(action_state.current_duration(&Action::Jump), Duration::ZERO);
assert_eq!(
action_state.previous_duration(&Action::Jump),
Duration::ZERO
);
let t0 = Instant::now();
let t1 = t0 + Duration::new(1, 0);
action_state.tick(t1, t0);
assert_eq!(action_state.instant_started(&Action::Jump), Some(t0));
assert_eq!(action_state.current_duration(&Action::Jump), t1 - t0);
assert_eq!(
action_state.previous_duration(&Action::Jump),
Duration::ZERO
);
let t2 = t1 + Duration::new(5, 0);
action_state.tick(t2, t1);
assert_eq!(action_state.instant_started(&Action::Jump), Some(t0));
assert_eq!(action_state.current_duration(&Action::Jump), t2 - t0);
assert_eq!(
action_state.previous_duration(&Action::Jump),
Duration::ZERO
);
action_state.release(&Action::Jump);
assert_eq!(action_state.instant_started(&Action::Jump), None);
assert_eq!(action_state.current_duration(&Action::Jump), Duration::ZERO);
assert_eq!(action_state.previous_duration(&Action::Jump), t2 - t0);
}
}