#![cfg(feature = "keyboard")]
use bevy::MinimalPlugins;
use bevy::input::InputPlugin;
use bevy::prelude::*;
use bevy::time::TimeUpdateStrategy;
use leafwing_input_manager::action_state::ActionState;
use leafwing_input_manager::input_map::InputMap;
use leafwing_input_manager::plugin::InputManagerPlugin;
use leafwing_input_manager::prelude::Buttonlike;
use leafwing_input_manager_macros::Actionlike;
use std::time::Duration;
#[derive(Actionlike, Clone, Copy, Debug, Reflect, PartialEq, Eq, Hash)]
enum TestAction {
Up,
}
#[derive(Resource, Default)]
struct UpdateCounter {
just_pressed: usize,
}
#[derive(Resource, Default)]
struct FixedUpdateCounter {
run: usize,
just_pressed: usize,
}
fn build_app(fixed_timestep: Duration, frame_timestep: Duration) -> App {
let mut app = App::new();
app.add_plugins(MinimalPlugins)
.add_plugins(InputPlugin)
.add_plugins(InputManagerPlugin::<TestAction>::default())
.init_resource::<UpdateCounter>()
.init_resource::<FixedUpdateCounter>()
.init_resource::<ActionState<TestAction>>()
.insert_resource(InputMap::<TestAction>::new([(
TestAction::Up,
KeyCode::ArrowUp,
)]))
.insert_resource(Time::<Fixed>::from_duration(fixed_timestep))
.insert_resource(TimeUpdateStrategy::ManualDuration(frame_timestep));
app.add_systems(Update, update_counter);
app.add_systems(FixedUpdate, fixed_update_counter);
let startup = app.world().resource::<Time<Real>>().startup();
app.world_mut()
.resource_mut::<Time<Real>>()
.update_with_instant(startup);
app
}
fn fixed_update_counter(
mut counter: ResMut<FixedUpdateCounter>,
action: Res<ActionState<TestAction>>,
) {
if action.just_pressed(&TestAction::Up) {
counter.just_pressed += 1;
}
counter.run += 1;
}
fn update_counter(mut counter: ResMut<UpdateCounter>, action: Res<ActionState<TestAction>>) {
if action.just_pressed(&TestAction::Up) {
counter.just_pressed += 1;
}
}
fn reset_counters(app: &mut App) {
let mut fixed_update_counters = app.world_mut().resource_mut::<FixedUpdateCounter>();
fixed_update_counters.run = 0;
fixed_update_counters.just_pressed = 0;
let mut update_counters = app.world_mut().resource_mut::<UpdateCounter>();
update_counters.just_pressed = 0;
}
fn check_fixed_update_run_count(app: &mut App, expected: usize) {
assert_eq!(
app.world()
.get_resource::<FixedUpdateCounter>()
.unwrap()
.run,
expected,
"FixedUpdate schedule should have run {expected} times"
);
}
fn check_fixed_update_just_pressed_count(app: &mut App, expected: usize) {
assert_eq!(
app.world()
.get_resource::<FixedUpdateCounter>()
.unwrap()
.just_pressed,
expected,
"Button should have been just_pressed {expected} times during the FixedUpdate schedule"
);
}
fn check_update_just_pressed_count(app: &mut App, expected: usize) {
assert_eq!(
app.world()
.get_resource::<UpdateCounter>()
.unwrap()
.just_pressed,
expected,
"Button should have been just_pressed {expected} times during the Update schedule"
);
}
#[test]
fn frame_without_fixed_timestep() {
let mut app = build_app(Duration::from_millis(10), Duration::from_millis(9));
KeyCode::ArrowUp.press(app.world_mut());
app.update();
check_update_just_pressed_count(&mut app, 1);
check_fixed_update_run_count(&mut app, 0);
reset_counters(&mut app);
app.update();
check_update_just_pressed_count(&mut app, 0);
check_fixed_update_run_count(&mut app, 1);
check_fixed_update_just_pressed_count(&mut app, 1);
reset_counters(&mut app);
app.update();
check_update_just_pressed_count(&mut app, 0);
check_fixed_update_run_count(&mut app, 1);
check_fixed_update_just_pressed_count(&mut app, 0);
reset_counters(&mut app);
#[cfg(feature = "timing")]
assert_eq!(
app.world()
.get_resource::<ActionState<TestAction>>()
.unwrap()
.current_duration(&TestAction::Up),
Duration::from_millis(18)
);
}
#[test]
fn frame_with_two_fixed_timestep() {
let mut app = build_app(Duration::from_millis(4), Duration::from_millis(9));
KeyCode::ArrowUp.press(app.world_mut());
app.update();
check_update_just_pressed_count(&mut app, 1);
check_fixed_update_run_count(&mut app, 2);
check_fixed_update_just_pressed_count(&mut app, 1);
reset_counters(&mut app);
app.update();
check_update_just_pressed_count(&mut app, 0);
check_fixed_update_run_count(&mut app, 2);
check_fixed_update_just_pressed_count(&mut app, 0);
reset_counters(&mut app);
#[cfg(feature = "timing")]
assert_eq!(
app.world()
.get_resource::<ActionState<TestAction>>()
.unwrap()
.current_duration(&TestAction::Up),
Duration::from_millis(18)
);
}