life: audio toggle, ui play/plause mute/playAudio toggle

main
Elijah Voigt 1 month ago
parent be242dbb1f
commit 9069c0b29e

Binary file not shown.

After

Width:  |  Height:  |  Size: 232 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 368 B

@ -22,10 +22,10 @@ fn main() {
.init_resource::<Coordinates>()
.init_resource::<CellAssets>()
.init_resource::<Panning>()
.init_state::<SimulationState>()
.init_state::<SimulationPlayback>()
.init_state::<AudioPlayback>()
.insert_resource(GlobalVolume::new(Volume::Linear(1.0)))
.add_message::<Lifecycle>()
.add_message::<SimulationState>()
.add_systems(Startup, setup)
.add_systems(Startup, load_audio_tones)
.add_systems(Startup, load_materials)
@ -36,7 +36,9 @@ fn main() {
)
.add_systems(
Update,
modulate_volume, // TODO: .run_if(any_component_added::<AudioSink>)
// Run if any component added/removed: AudioSink
// Run if state changed: AudioPlayback
control_volume,
)
.add_systems(Update, grid_gizmo)
.add_systems(
@ -57,12 +59,12 @@ fn main() {
.add_systems(
Update,
simulation_step
.run_if(in_state(SimulationState::Run))
.run_if(in_state(SimulationPlayback::Run))
.run_if(cooldown_secs(FRAME_DURATION)),
)
.add_systems(
Update,
simulation_step.run_if(on_message::<SimulationState>),
simulation_step.run_if(state_changed::<SimulationPlayback>),
)
.add_systems(
Update,
@ -71,6 +73,14 @@ fn main() {
.add_systems(Update, cell_lifecycle.run_if(on_message::<Lifecycle>))
.add_systems(Update, mouse_pan.run_if(on_message::<MouseMotion>))
.add_systems(Update, set_pan_state)
.add_systems(
Update,
toggle_state_entities::<SimulationPlayback>.run_if(state_changed::<SimulationPlayback>),
)
.add_systems(
Update,
toggle_state_entities::<AudioPlayback>.run_if(state_changed::<AudioPlayback>),
)
.add_observer(on_add_ui_button)
.add_observer(on_add_coordinates)
.run();
@ -78,6 +88,13 @@ fn main() {
const SCALE: f32 = 100.0;
#[derive(States, Debug, Default, Hash, PartialEq, Eq, Clone, Component)]
enum AudioPlayback {
#[default]
Mute,
Play,
}
#[derive(Debug, Component, PartialEq)]
#[require(Visibility, Transform)]
enum UiButton {
@ -87,6 +104,8 @@ enum UiButton {
Play,
ZoomOut,
ZoomIn,
PlayAudio,
MuteAudio,
}
impl UiButton {
@ -98,6 +117,8 @@ impl UiButton {
Self::Play => "forward.png",
Self::ZoomOut => "zoomOut.png",
Self::ZoomIn => "zoomIn.png",
Self::PlayAudio => "audioOn.png",
Self::MuteAudio => "audioOff.png",
}
}
}
@ -171,32 +192,38 @@ fn setup(mut commands: Commands) {
))
.with_children(|parent| {
parent.spawn(UiButton::Power).observe(shutdown);
// TODO: Play/Pause Toggle
parent.spawn(UiButton::Pause).observe(pause_sim);
parent.spawn(UiButton::Play).observe(play_sim);
// TODO: Reset button
parent
.spawn((UiButton::Pause, SimulationPlayback::Run))
.observe(pause_sim);
parent
.spawn((UiButton::Play, SimulationPlayback::Pause))
.observe(play_sim);
parent.spawn(UiButton::Step).observe(step_sim);
parent.spawn(UiButton::ZoomOut).observe(zoom_out);
parent.spawn(UiButton::ZoomIn).observe(zoom_in);
// TODO: Reset button
// TODO: Mute/Unmute Toggle
parent
.spawn((UiButton::MuteAudio, AudioPlayback::Play))
.observe(mute_audio);
parent
.spawn((UiButton::PlayAudio, AudioPlayback::Mute))
.observe(play_audio);
});
fn shutdown(_trigger: On<Pointer<Press>>, mut writer: MessageWriter<AppExit>) {
writer.write(AppExit::Success);
}
fn pause_sim(_trigger: On<Pointer<Press>>, mut next: ResMut<NextState<SimulationState>>) {
next.set(SimulationState::Pause);
fn play_sim(_trigger: On<Pointer<Press>>, mut next: ResMut<NextState<SimulationPlayback>>) {
// Set simulation state
next.set(SimulationPlayback::Run);
}
fn step_sim(
_trigger: On<Pointer<Press>>,
mut writer: MessageWriter<SimulationState>,
mut next: ResMut<NextState<SimulationState>>,
) {
next.set(SimulationState::Step);
writer.write(SimulationState::Step);
fn pause_sim(_trigger: On<Pointer<Press>>, mut next: ResMut<NextState<SimulationPlayback>>) {
// Set simulation state
next.set(SimulationPlayback::Pause);
}
fn play_sim(_trigger: On<Pointer<Press>>, mut next: ResMut<NextState<SimulationState>>) {
next.set(SimulationState::Run);
fn step_sim(_trigger: On<Pointer<Press>>, mut next: ResMut<NextState<SimulationPlayback>>) {
next.set(SimulationPlayback::Step);
}
fn zoom_out(_trigger: On<Pointer<Press>>, mut projection: Query<&mut Projection>) {
projection.iter_mut().for_each(|mut p| match *p {
@ -214,6 +241,12 @@ fn setup(mut commands: Commands) {
_ => todo!(),
});
}
fn play_audio(_trigger: On<Pointer<Press>>, mut next: ResMut<NextState<AudioPlayback>>) {
next.set(AudioPlayback::Play);
}
fn mute_audio(_trigger: On<Pointer<Press>>, mut next: ResMut<NextState<AudioPlayback>>) {
next.set(AudioPlayback::Mute);
}
}
#[derive(Debug, Default, Clone, PartialEq, Hash, Eq, Component, Resource)]
@ -398,8 +431,8 @@ fn assert_cell_uniqueness(q: Query<(Entity, &Coordinates), With<Cell>>) {
})
}
#[derive(States, Debug, Default, Hash, PartialEq, Eq, Clone, Message)]
enum SimulationState {
#[derive(States, Debug, Default, Hash, PartialEq, Eq, Clone, Component)]
enum SimulationPlayback {
#[default]
Pause,
Run,
@ -532,13 +565,13 @@ fn cooldown_secs(input: f32) -> impl FnMut(Local<Timer>, Res<Time>) -> bool + Cl
// If in Pause state, keep Pauses button light, or blinking or outlined or something.
fn visualize_ui_state(
mut query: Query<(&UiButton, &mut Outline)>,
state: Res<State<SimulationState>>,
state: Res<State<SimulationPlayback>>,
) {
query.iter_mut().for_each(|(uib, mut o)| {
o.color = match (uib, state.get()) {
(UiButton::Pause, SimulationState::Pause) => BLACK.into(),
(UiButton::Step, SimulationState::Step) => BLACK.into(),
(UiButton::Play, SimulationState::Run) => BLACK.into(),
(UiButton::Pause, SimulationPlayback::Pause) => BLACK.into(),
(UiButton::Step, SimulationPlayback::Step) => BLACK.into(),
(UiButton::Play, SimulationPlayback::Run) => BLACK.into(),
_ => Color::NONE,
}
});
@ -620,10 +653,19 @@ fn load_audio_tones(mut pitches: ResMut<Assets<Pitch>>, mut cell_assets: ResMut<
debug_assert!(cell_assets.pitches.iter().len() == 25);
}
// TODO: Why does audio only play when running simulation?
fn modulate_volume(mut gv: ResMut<GlobalVolume>, active: Query<Entity, With<AudioSink>>) {
let ratio = 1.0 / active.count() as f32;
gv.volume = Volume::Linear(ratio);
fn control_volume(state: ResMut<State<AudioPlayback>>, mut sinks: Query<&mut AudioSink>) {
match state.get() {
AudioPlayback::Play => {
let ratio = 1.0 / sinks.count() as f32;
let volume = Volume::Linear(ratio);
sinks.iter_mut().for_each(|mut sink| {
sink.set_volume(volume);
})
},
AudioPlayback::Mute => sinks.iter_mut().for_each(|mut sink| {
sink.set_volume(Volume::SILENT);
}),
}
}
fn load_materials(
@ -710,3 +752,18 @@ fn set_pan_state(
fn is_panning(panning: Res<Panning>) -> bool {
panning.0
}
fn toggle_state_entities<S: States + Component>(
mut query: Query<(&mut Visibility, &S)>,
state: Res<State<S>>,
) {
query.iter_mut().for_each(|(mut v, s)| {
*v = if state.get() == s {
Visibility::Inherited
} else {
Visibility::Hidden
};
});
}
// TODO: Do not spawn cell when clicking UI

Loading…
Cancel
Save