life: pan sorta kinda works

main
Elijah Voigt 1 month ago
parent 84dd94ed3a
commit 58aea7b02d

@ -2,7 +2,10 @@
use std::time::Duration; use std::time::Duration;
use bevy::{audio::Volume, picking::hover::Hovered, platform::collections::HashMap}; use bevy::{
audio::Volume, input::mouse::{AccumulatedMouseMotion, MouseMotion}, picking::hover::Hovered,
platform::collections::HashMap,
};
use engine::*; use engine::*;
const TILE: &str = "tileGrey_01.png"; const TILE: &str = "tileGrey_01.png";
@ -30,7 +33,7 @@ fn main() {
) )
.add_systems( .add_systems(
Update, Update,
modulate_volume // TODO: .run_if(any_component_added::<AudioSink>) modulate_volume, // TODO: .run_if(any_component_added::<AudioSink>)
) )
.add_systems(Update, grid_gizmo) .add_systems(Update, grid_gizmo)
.add_systems( .add_systems(
@ -53,10 +56,6 @@ fn main() {
.run_if(in_state(SimulationState::Run)) .run_if(in_state(SimulationState::Run))
.run_if(cooldown_secs(FRAME_DURATION)), .run_if(cooldown_secs(FRAME_DURATION)),
) )
.add_systems(
Update,
start_audio_synced.run_if(cooldown_secs(FRAME_DURATION))
)
.add_systems( .add_systems(
Update, Update,
simulation_step.run_if(on_message::<SimulationState>), simulation_step.run_if(on_message::<SimulationState>),
@ -66,6 +65,7 @@ fn main() {
visualize_ui_state.run_if(on_message::<Pointer<Click>>), visualize_ui_state.run_if(on_message::<Pointer<Click>>),
) )
.add_systems(Update, cell_lifecycle.run_if(on_message::<Lifecycle>)) .add_systems(Update, cell_lifecycle.run_if(on_message::<Lifecycle>))
.add_systems(Update, mouse_pan.run_if(on_message::<MouseMotion>))
.add_observer(on_add_ui_button) .add_observer(on_add_ui_button)
.add_observer(on_add_coordinates) .add_observer(on_add_coordinates)
.run(); .run();
@ -166,11 +166,14 @@ fn setup(mut commands: Commands) {
)) ))
.with_children(|parent| { .with_children(|parent| {
parent.spawn(UiButton::Power).observe(shutdown); parent.spawn(UiButton::Power).observe(shutdown);
// TODO: Play/Pause Toggle
parent.spawn(UiButton::Pause).observe(pause_sim); parent.spawn(UiButton::Pause).observe(pause_sim);
parent.spawn(UiButton::Step).observe(step_sim);
parent.spawn(UiButton::Play).observe(play_sim); parent.spawn(UiButton::Play).observe(play_sim);
parent.spawn(UiButton::Step).observe(step_sim);
parent.spawn(UiButton::ZoomOut).observe(zoom_out); parent.spawn(UiButton::ZoomOut).observe(zoom_out);
parent.spawn(UiButton::ZoomIn).observe(zoom_in); parent.spawn(UiButton::ZoomIn).observe(zoom_in);
// TODO: Reset button
// TODO: Mute/Unmute Toggle
}); });
fn shutdown(_trigger: On<Pointer<Press>>, mut writer: MessageWriter<AppExit>) { fn shutdown(_trigger: On<Pointer<Press>>, mut writer: MessageWriter<AppExit>) {
@ -261,7 +264,7 @@ impl Coordinates {
fn as_color(&self) -> Color { fn as_color(&self) -> Color {
// hue (0..360.0) evenly spaced x in -2..4 // hue (0..360.0) evenly spaced x in -2..4
// chroma (0..1) evenly spaced y in -2..5 // chroma (0..1) evenly spaced y in -2..5
let hue = (360.0 / 5.0) * ((self.x + 2) % 5) as f32; let hue = (360.0 / 5.0) * ((self.x + 2) % 5) as f32;
let chroma = (1.0 / 5.0) * ((self.y + 2) % 5) as f32; let chroma = (1.0 / 5.0) * ((self.y + 2) % 5) as f32;
let lightness = (1.0 / 5.0) * ((self.y + 2) % 5) as f32; let lightness = (1.0 / 5.0) * ((self.y + 2) % 5) as f32;
Color::Oklcha(Oklcha { Color::Oklcha(Oklcha {
@ -272,7 +275,6 @@ impl Coordinates {
}) })
} }
fn as_cell_pitch(&self) -> CellPitch { fn as_cell_pitch(&self) -> CellPitch {
debug!("Generating cell pitch for {:?}", self); debug!("Generating cell pitch for {:?}", self);
@ -288,11 +290,15 @@ impl Coordinates {
let octave = ((self.y + 2).abs() % 5) - 2; let octave = ((self.y + 2).abs() % 5) - 2;
debug_assert!((-2..=2).contains(&octave)); debug_assert!((-2..=2).contains(&octave));
debug!("\t{:?}", CellPitch { note: note.clone(), octave }); debug!(
"\t{:?}",
CellPitch {
note: note.clone(),
octave
}
);
CellPitch { CellPitch { note, octave }
note, octave
}
} }
} }
@ -324,17 +330,9 @@ fn on_add_coordinates(
commands.entity(trigger.entity).insert(t); commands.entity(trigger.entity).insert(t);
let p = cell_assets.pitches.get(&c.as_cell_pitch()).unwrap(); let p = cell_assets.pitches.get(&c.as_cell_pitch()).unwrap();
commands.entity(trigger.entity).insert((AudioPlayer(p.clone()), PlaybackSettings::ONCE)); commands
} .entity(trigger.entity)
.insert((AudioPlayer(p.clone()), PlaybackSettings::ONCE));
/// All audio starts paused so we can keep them in sync
/// This starts audios when the system is triggered, which is on a timer
fn start_audio_synced(query: Query<&AudioSink, With<Cell>>) {
query.iter().for_each(|sink| {
if sink.is_paused() {
sink.play()
}
});
} }
/// When the cursor moves, update the Coordiantes /// When the cursor moves, update the Coordiantes
@ -603,6 +601,10 @@ fn load_audio_tones(mut pitches: ResMut<Assets<Pitch>>, mut cell_assets: ResMut<
}; };
let frequency = cell_pitch.to_frequency(); let frequency = cell_pitch.to_frequency();
let duration = Duration::from_secs(100); let duration = Duration::from_secs(100);
debug!(
"Adding Pitch frequency: {:?} duration: {:?}",
frequency, duration
);
let handle = pitches.add(Pitch { let handle = pitches.add(Pitch {
frequency, frequency,
duration, duration,
@ -613,6 +615,7 @@ fn load_audio_tones(mut pitches: ResMut<Assets<Pitch>>, mut cell_assets: ResMut<
debug_assert!(cell_assets.pitches.iter().len() == 25); 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>>) { fn modulate_volume(mut gv: ResMut<GlobalVolume>, active: Query<Entity, With<AudioSink>>) {
let ratio = 1.0 / active.count() as f32; let ratio = 1.0 / active.count() as f32;
gv.volume = Volume::Linear(ratio); gv.volume = Volume::Linear(ratio);
@ -630,11 +633,15 @@ fn load_materials(
vertical.iter().for_each(|&x| { vertical.iter().for_each(|&x| {
horizontal.iter().for_each(|&y| { horizontal.iter().for_each(|&y| {
let c = Coordinates { x, y }; let c = Coordinates { x, y };
let pitch = c.as_cell_pitch(); let pitch = c.as_cell_pitch();
let handle = { let handle = {
let color = c.as_color(); let color = c.as_color();
let texture = Some(tile_handle.clone()); let texture = Some(tile_handle.clone());
let color_material = ColorMaterial { color, texture, ..default() }; let color_material = ColorMaterial {
color,
texture,
..default()
};
materials.add(color_material) materials.add(color_material)
}; };
cell_assets.materials.insert(pitch, handle); cell_assets.materials.insert(pitch, handle);
@ -646,3 +653,35 @@ fn load_materials(
fn load_meshes(mut cell_assets: ResMut<CellAssets>, mut meshes: ResMut<Assets<Mesh>>) { fn load_meshes(mut cell_assets: ResMut<CellAssets>, mut meshes: ResMut<Assets<Mesh>>) {
cell_assets.mesh = meshes.add(Rectangle::new(SCALE, SCALE)); cell_assets.mesh = meshes.add(Rectangle::new(SCALE, SCALE));
} }
// TODO: Do not place piece if panning
// TODO: Tie cursor to real world space, not pixels
fn mouse_pan(
mouse_motion: Res<AccumulatedMouseMotion>,
button: Res<ButtonInput<MouseButton>>,
mut camera: Query<(&Camera, &mut Transform, &GlobalTransform), With<Camera2d>>,
window: Query<&Window>,
) {
if button.pressed(MouseButton::Left) {
let delta = mouse_motion.delta;
camera.iter_mut().for_each(|(c, mut t, gt)| {
window.iter().for_each(|w| {
let Some(curr_cursor_position) = w.cursor_position() else {
return;
};
let old_cursor_position = curr_cursor_position - delta / w.scale_factor();
let Ok(curr_world) = c.viewport_to_world_2d(gt, curr_cursor_position) else {
return;
};
let Ok(old_world) = c.viewport_to_world_2d(gt, old_cursor_position) else {
return;
};
let delta_world = old_world - curr_world;
t.translation.x += delta_world.x / 7.0;
t.translation.y += delta_world.y / 7.0;
});
});
}
}

@ -0,0 +1,5 @@
use engine::*;
fn main() {
App::new().add_plugins(DefaultPlugins).run();
}

@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -euo pipefail set -euo pipefail
for dir in $(find . -mindepth 2 -maxdepth 2 -name "Cargo.toml" -not -path "*/target/*" -exec dirname {} \;); for dir in $(find . -mindepth 2 -maxdepth 2 -name "Cargo.toml" -not -path "*/target/*" | xargs -I{} dirname {} );
do do
cargo fmt --manifest-path "$dir/Cargo.toml"; cargo fmt --manifest-path "$dir/Cargo.toml";
done done

Loading…
Cancel
Save