You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

138 lines
4.3 KiB
Rust

use super::*;
pub(crate) struct GameActionsPlugin;
impl Plugin for GameActionsPlugin {
fn build(&self, app: &mut App) {
app.add_plugins((
ActionsPlugin::<SimAction>::new()
.bind(SimAction::Toggle, [Binding::Key(KeyCode::Space)])
.bind(SimAction::Step, [Binding::Key(KeyCode::KeyN)])
.bind(SimAction::Reset, [Binding::Key(KeyCode::KeyR)]),
ActionsPlugin::<AudioAction>::new()
.bind(AudioAction::Toggle, [Binding::Key(KeyCode::KeyM)]),
ActionsPlugin::<Action>::new()
.bind(Action::ZoomIn, [Binding::Key(KeyCode::Equal)])
.bind(Action::ZoomOut, [Binding::Key(KeyCode::Minus)])
.bind(Action::Quit, [Binding::Key(KeyCode::Escape)]),
));
}
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, GameAction, Default)]
pub(crate) enum SimAction {
#[action_handler(SimAction::toggle)]
Toggle,
#[action_handler(SimAction::step)]
Step,
#[action_handler(SimAction::reset)]
Reset,
#[action_handler(SimAction::wipe)]
Wipe,
#[default]
None,
}
impl SimAction {
/// When the user toggles between Play/Pause simulation, just update the state
fn toggle(
curr: Res<State<SimulationPlayback>>,
mut next: ResMut<NextState<SimulationPlayback>>,
mut last_board_state: ResMut<LastBoardState>,
coordinates: Query<&Coordinates, With<Cell>>,
) {
next.set(match curr.get() {
SimulationPlayback::Run | SimulationPlayback::Step => {
// Run | Step -> Pause
SimulationPlayback::Pause
}
SimulationPlayback::Pause => {
// Capture current state before running
last_board_state.coordinates = coordinates.iter().cloned().collect();
// Pause -> Run
SimulationPlayback::Run
}
});
}
// When the user wants to step the simulation, just enter the SimulationStep state
// TODO: Should switch back to Pause automatically after step if Step is the current state
fn step(mut next: ResMut<NextState<SimulationPlayback>>) {
next.set(SimulationPlayback::Step);
}
// Reset board to last saved state (before running, or before wiping)
fn reset(
last_board_state: Res<LastBoardState>,
mut lifecycle: MessageWriter<Lifecycle>,
cells: Query<Entity, With<Cell>>,
mut commands: Commands,
) {
// TODO: reconcile board instead of despawn/spawning the world
cells.iter().for_each(|e| {
commands.entity(e).despawn();
});
last_board_state.coordinates.iter().for_each(|c| {
lifecycle.write(Lifecycle::Alive(c.clone()));
});
}
// Wipe all cells from the board
fn wipe(cells: Query<Entity, With<Cell>>, mut commands: Commands) {
cells.iter().for_each(|e| {
commands.entity(e).despawn();
});
}
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, GameAction, Default)]
pub(crate) enum Action {
#[action_handler(Action::zoom_in)]
ZoomIn,
#[action_handler(Action::zoom_out)]
ZoomOut,
#[action_handler(Action::quit)]
Quit,
#[default]
None,
}
impl Action {
fn zoom_in(mut projection: Query<&mut Projection>) {
projection.iter_mut().for_each(|mut p| match *p {
Projection::Orthographic(ref mut o) => {
o.scale *= 0.5;
}
_ => todo!(),
});
}
fn zoom_out(mut projection: Query<&mut Projection>) {
projection.iter_mut().for_each(|mut p| match *p {
Projection::Orthographic(ref mut o) => {
o.scale /= 0.5;
}
_ => todo!(),
});
}
fn quit(mut writer: MessageWriter<AppExit>) {
writer.write(AppExit::Success);
}
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, GameAction, Default)]
pub(crate) enum AudioAction {
#[action_handler(AudioAction::toggle)]
Toggle,
#[default]
None,
}
impl AudioAction {
fn toggle(curr: Res<State<AudioPlayback>>, mut next: ResMut<NextState<AudioPlayback>>) {
next.set(match curr.get() {
AudioPlayback::Play => AudioPlayback::Mute,
AudioPlayback::Mute => AudioPlayback::Play,
});
}
}