|
|
|
@ -1,15 +1,17 @@
|
|
|
|
// TODO:
|
|
|
|
// TODO:
|
|
|
|
// * Fix randomly audio not working
|
|
|
|
|
|
|
|
// * Lock down system scheduling/run_if conditions
|
|
|
|
// * Lock down system scheduling/run_if conditions
|
|
|
|
// * UI widget explaining rules/hotkeys
|
|
|
|
// * Performance: have a limit on per-note+octave sounds
|
|
|
|
|
|
|
|
// * Use a finite set of N audio entities and scale volume instead of
|
|
|
|
|
|
|
|
// spawning a bunch of audio entities which is causing issues at >100
|
|
|
|
|
|
|
|
// cells
|
|
|
|
|
|
|
|
// * Stop creating cells when I didn't mean to (clicking UI, click + dragging)
|
|
|
|
|
|
|
|
// * Keep some controls open when main ui panel is closed
|
|
|
|
|
|
|
|
// * Exclude power button from web build
|
|
|
|
// * Show shadow of piece (same tile, just with alpha transparency)
|
|
|
|
// * Show shadow of piece (same tile, just with alpha transparency)
|
|
|
|
// * Start with an interesting pattern
|
|
|
|
// * Dark mode
|
|
|
|
// * UI minimize widgets (mostly done)
|
|
|
|
|
|
|
|
// * Indicate to click on the UI
|
|
|
|
|
|
|
|
// * Add "follow action" that adjusts camera to zoom in/out/move to see everything
|
|
|
|
|
|
|
|
// * Make click and drag feel better
|
|
|
|
// * Make click and drag feel better
|
|
|
|
// * Add arrow keys to move around
|
|
|
|
// * Add arrow keys to move around
|
|
|
|
// * web/wasm build
|
|
|
|
// * "Follow" enhancement: Zoom in/out
|
|
|
|
#![allow(clippy::complexity)]
|
|
|
|
#![allow(clippy::complexity)]
|
|
|
|
// Only because of FromTemplat macros unfortunately...
|
|
|
|
// Only because of FromTemplat macros unfortunately...
|
|
|
|
#![allow(dead_code)]
|
|
|
|
#![allow(dead_code)]
|
|
|
|
@ -52,23 +54,52 @@ fn main() {
|
|
|
|
load_meshes,
|
|
|
|
load_meshes,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
.configure_sets(
|
|
|
|
|
|
|
|
Update,
|
|
|
|
|
|
|
|
(GameSet::Plan, GameSet::Apply, GameSet::React).chain(),
|
|
|
|
|
|
|
|
)
|
|
|
|
// Cell management/Simulation
|
|
|
|
// Cell management/Simulation
|
|
|
|
.add_systems(
|
|
|
|
.add_systems(
|
|
|
|
Update,
|
|
|
|
Update,
|
|
|
|
|
|
|
|
(
|
|
|
|
|
|
|
|
// Produce lifecycle messages
|
|
|
|
(
|
|
|
|
(
|
|
|
|
default_board.run_if(run_once),
|
|
|
|
default_board.run_if(run_once),
|
|
|
|
cell_lifecycle.run_if(on_message::<Lifecycle>),
|
|
|
|
|
|
|
|
update_grid_position.run_if(on_message::<CursorMoved>),
|
|
|
|
update_grid_position.run_if(on_message::<CursorMoved>),
|
|
|
|
de_spawn_cells
|
|
|
|
de_spawn_cells
|
|
|
|
.run_if(not(is_ui_hovered))
|
|
|
|
.run_if(not(is_ui_hovered))
|
|
|
|
.run_if(not(is_panning))
|
|
|
|
.run_if(not(is_panning))
|
|
|
|
.run_if(input_just_released(MouseButton::Left)),
|
|
|
|
.run_if(input_just_released(MouseButton::Left)),
|
|
|
|
simulation_step
|
|
|
|
simulation_step.run_if(
|
|
|
|
.run_if(in_state(SimulationPlayback::Run))
|
|
|
|
in_state(SimulationPlayback::Run)
|
|
|
|
.run_if(cooldown_secs(SIM_FRAME_DURATION)),
|
|
|
|
.and_then(cooldown_secs(SIM_FRAME_DURATION))
|
|
|
|
simulation_step.run_if(state_changed::<SimulationPlayback>),
|
|
|
|
.or_else(state_changed::<SimulationPlayback>),
|
|
|
|
|
|
|
|
),
|
|
|
|
pause_simulation.run_if(in_state(SimulationPlayback::Step)),
|
|
|
|
pause_simulation.run_if(in_state(SimulationPlayback::Step)),
|
|
|
|
update_material,
|
|
|
|
)
|
|
|
|
|
|
|
|
.in_set(GameSet::Plan),
|
|
|
|
|
|
|
|
// Apply lifecycle message
|
|
|
|
|
|
|
|
cell_lifecycle
|
|
|
|
|
|
|
|
.run_if(on_message::<Lifecycle>)
|
|
|
|
|
|
|
|
.in_set(GameSet::Apply),
|
|
|
|
|
|
|
|
// React to board changes
|
|
|
|
|
|
|
|
(
|
|
|
|
|
|
|
|
reassign_cell_pitch.run_if(resource_changed::<PitchMap>),
|
|
|
|
|
|
|
|
update_material.run_if(
|
|
|
|
|
|
|
|
any_component_added::<CellPitch>
|
|
|
|
|
|
|
|
.or_else(any_component_changed::<CellPitch>),
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
camera_follow
|
|
|
|
|
|
|
|
.run_if(in_state(SimulationPlayback::Run))
|
|
|
|
|
|
|
|
.run_if(any_component_changed::<Coordinates>),
|
|
|
|
|
|
|
|
update_camera_position
|
|
|
|
|
|
|
|
.run_if(in_state(SimulationPlayback::Run))
|
|
|
|
|
|
|
|
.run_if(not(query_condition_empty::<(
|
|
|
|
|
|
|
|
With<Camera>,
|
|
|
|
|
|
|
|
Changed<Coordinates>,
|
|
|
|
|
|
|
|
)>)),
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
.in_set(GameSet::React),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
)
|
|
|
|
// Audio Systems
|
|
|
|
// Audio Systems
|
|
|
|
@ -77,19 +108,29 @@ fn main() {
|
|
|
|
(
|
|
|
|
(
|
|
|
|
control_volume,
|
|
|
|
control_volume,
|
|
|
|
update_pitch_map_resource_ui.run_if(resource_changed::<PitchMap>),
|
|
|
|
update_pitch_map_resource_ui.run_if(resource_changed::<PitchMap>),
|
|
|
|
reassign_cell_pitch.run_if(resource_changed::<PitchMap>),
|
|
|
|
update_audio
|
|
|
|
update_audio,
|
|
|
|
.run_if(
|
|
|
|
|
|
|
|
any_component_added::<CellPitch>
|
|
|
|
|
|
|
|
.or_else(any_component_changed::<CellPitch>),
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
.in_set(GameSet::React),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
)
|
|
|
|
// Debugging
|
|
|
|
// Debugging
|
|
|
|
.add_systems(
|
|
|
|
.add_systems(
|
|
|
|
Update,
|
|
|
|
Update,
|
|
|
|
(
|
|
|
|
(
|
|
|
|
assert_cell_uniqueness.run_if(any_with_component::<Cell>),
|
|
|
|
|
|
|
|
grid_gizmo,
|
|
|
|
grid_gizmo,
|
|
|
|
update_debug_info_cell_count,
|
|
|
|
|
|
|
|
update_debug_info_coordinates,
|
|
|
|
update_debug_info_coordinates,
|
|
|
|
|
|
|
|
(
|
|
|
|
|
|
|
|
assert_cell_uniqueness
|
|
|
|
|
|
|
|
.run_if(any_with_component::<Cell>)
|
|
|
|
|
|
|
|
.after(update_material)
|
|
|
|
|
|
|
|
.after(update_audio),
|
|
|
|
|
|
|
|
update_debug_info_cell_count,
|
|
|
|
update_debug_info_active,
|
|
|
|
update_debug_info_active,
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
.in_set(GameSet::React),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
)
|
|
|
|
// Ui Controllers
|
|
|
|
// Ui Controllers
|
|
|
|
@ -116,6 +157,13 @@ fn main() {
|
|
|
|
|
|
|
|
|
|
|
|
const SCALE: f32 = 100.0;
|
|
|
|
const SCALE: f32 = 100.0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]
|
|
|
|
|
|
|
|
enum GameSet {
|
|
|
|
|
|
|
|
Plan,
|
|
|
|
|
|
|
|
Apply,
|
|
|
|
|
|
|
|
React,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Component, PartialEq, Clone, Default)]
|
|
|
|
#[derive(Component, PartialEq, Clone, Default)]
|
|
|
|
enum DebugInfo {
|
|
|
|
enum DebugInfo {
|
|
|
|
CellCount,
|
|
|
|
CellCount,
|
|
|
|
@ -157,11 +205,6 @@ enum UiButton {
|
|
|
|
ZoomIn,
|
|
|
|
ZoomIn,
|
|
|
|
PlayAudio,
|
|
|
|
PlayAudio,
|
|
|
|
MuteAudio,
|
|
|
|
MuteAudio,
|
|
|
|
AddHighOctave,
|
|
|
|
|
|
|
|
SubHighOctave,
|
|
|
|
|
|
|
|
AddLowOctave,
|
|
|
|
|
|
|
|
SubLowOctave,
|
|
|
|
|
|
|
|
Note,
|
|
|
|
|
|
|
|
Reset,
|
|
|
|
Reset,
|
|
|
|
Wipe,
|
|
|
|
Wipe,
|
|
|
|
#[default]
|
|
|
|
#[default]
|
|
|
|
@ -179,11 +222,6 @@ impl UiButton {
|
|
|
|
Self::ZoomIn => "zoomIn.png",
|
|
|
|
Self::ZoomIn => "zoomIn.png",
|
|
|
|
Self::PlayAudio => "audioOn.png",
|
|
|
|
Self::PlayAudio => "audioOn.png",
|
|
|
|
Self::MuteAudio => "audioOff.png",
|
|
|
|
Self::MuteAudio => "audioOff.png",
|
|
|
|
Self::AddHighOctave => "todo.png",
|
|
|
|
|
|
|
|
Self::SubHighOctave => "todo.png",
|
|
|
|
|
|
|
|
Self::AddLowOctave => "todo.png",
|
|
|
|
|
|
|
|
Self::SubLowOctave => "todo.png",
|
|
|
|
|
|
|
|
Self::Note => "todo.png",
|
|
|
|
|
|
|
|
Self::Reset => "return.png",
|
|
|
|
Self::Reset => "return.png",
|
|
|
|
Self::Wipe => "trashcan.png",
|
|
|
|
Self::Wipe => "trashcan.png",
|
|
|
|
Self::None => todo!(),
|
|
|
|
Self::None => todo!(),
|
|
|
|
@ -264,6 +302,7 @@ fn ui_toggle_button<A: Scene, B: Scene>(
|
|
|
|
fn the_camera() -> impl Scene {
|
|
|
|
fn the_camera() -> impl Scene {
|
|
|
|
bsn! {
|
|
|
|
bsn! {
|
|
|
|
Camera2d
|
|
|
|
Camera2d
|
|
|
|
|
|
|
|
Coordinates
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@ -434,25 +473,47 @@ fn primary_ui() -> impl Scene {
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn description_text() -> impl Scene {
|
|
|
|
bsn! {
|
|
|
|
bsn! {
|
|
|
|
|
|
|
|
subpane()
|
|
|
|
Node {
|
|
|
|
Node {
|
|
|
|
display: Display::Flex,
|
|
|
|
display: Display::Flex,
|
|
|
|
flex_direction: FlexDirection::Column,
|
|
|
|
flex_direction: FlexDirection::Column,
|
|
|
|
|
|
|
|
align_items: AlignItems::Stretch,
|
|
|
|
justify_content: JustifyContent::Start,
|
|
|
|
justify_content: JustifyContent::Start,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Transform
|
|
|
|
text_setup()
|
|
|
|
pane()
|
|
|
|
|
|
|
|
Children [
|
|
|
|
|
|
|
|
pane_header()
|
|
|
|
|
|
|
|
on(toggle_main_ui)
|
|
|
|
|
|
|
|
// todo: toggle main ui
|
|
|
|
|
|
|
|
Children [
|
|
|
|
|
|
|
|
Text("Conways Game of Life With Sound") ThemedText,
|
|
|
|
|
|
|
|
],
|
|
|
|
|
|
|
|
pane_body()
|
|
|
|
|
|
|
|
MainUi::Visible
|
|
|
|
|
|
|
|
ToggleStateVisible
|
|
|
|
|
|
|
|
Children [
|
|
|
|
Children [
|
|
|
|
|
|
|
|
Text("Welcome to a little experiment I made: adding sound to Conways Game of Life") ThemedText,
|
|
|
|
|
|
|
|
Text("---") ThemedText,
|
|
|
|
|
|
|
|
Text("The buttons above control (in order)") ThemedText,
|
|
|
|
|
|
|
|
Text("Quit the game") ThemedText,
|
|
|
|
|
|
|
|
Text("Start/Pause the simulation") ThemedText,
|
|
|
|
|
|
|
|
Text("Step the simulation") ThemedText,
|
|
|
|
|
|
|
|
Text("Reset the world state") ThemedText,
|
|
|
|
|
|
|
|
Text("Wipe the world state") ThemedText,
|
|
|
|
|
|
|
|
Text("Zoom in/out") ThemedText,
|
|
|
|
|
|
|
|
Text("Toggle sound on/off") ThemedText,
|
|
|
|
|
|
|
|
Text("---") ThemedText,
|
|
|
|
|
|
|
|
Text("Below that are the notes you can toggle on/off") ThemedText,
|
|
|
|
|
|
|
|
Text("And below that are the number of octaves for each note") ThemedText,
|
|
|
|
|
|
|
|
Text("Notes are color coded horizontally") ThemedText,
|
|
|
|
|
|
|
|
Text("Octaves are color coded vertically") ThemedText,
|
|
|
|
|
|
|
|
Text("---") ThemedText,
|
|
|
|
|
|
|
|
Text("The camera automatically follows the action") ThemedText,
|
|
|
|
|
|
|
|
Text("---") ThemedText,
|
|
|
|
|
|
|
|
Text("Hotkyes") ThemedText,
|
|
|
|
|
|
|
|
Text("* Space: Play/Pause Simulation") ThemedText,
|
|
|
|
|
|
|
|
Text("* m: Mute/Play Audio") ThemedText,
|
|
|
|
|
|
|
|
Text("* r: Reset Simulation") ThemedText,
|
|
|
|
|
|
|
|
Text("* n: Next Simulation Step") ThemedText,
|
|
|
|
|
|
|
|
Text("* -/=: Zoom In/Out") ThemedText,
|
|
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn controls() -> impl Scene {
|
|
|
|
|
|
|
|
bsn! {
|
|
|
|
subpane()
|
|
|
|
subpane()
|
|
|
|
Node {
|
|
|
|
Node {
|
|
|
|
display: Display::Flex,
|
|
|
|
display: Display::Flex,
|
|
|
|
@ -490,7 +551,12 @@ fn primary_ui() -> impl Scene {
|
|
|
|
ui_toggle_button((UiButton::MuteAudio, bsn! { AudioPlayback::Mute }), (UiButton::PlayAudio, bsn! { AudioPlayback::Play }))
|
|
|
|
ui_toggle_button((UiButton::MuteAudio, bsn! { AudioPlayback::Mute }), (UiButton::PlayAudio, bsn! { AudioPlayback::Play }))
|
|
|
|
ActionSource<AudioAction>(AudioAction::Toggle),
|
|
|
|
ActionSource<AudioAction>(AudioAction::Toggle),
|
|
|
|
]
|
|
|
|
]
|
|
|
|
],
|
|
|
|
]
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn notes() -> impl Scene {
|
|
|
|
|
|
|
|
bsn! {
|
|
|
|
subpane()
|
|
|
|
subpane()
|
|
|
|
Children [
|
|
|
|
Children [
|
|
|
|
subpane_header() Children [
|
|
|
|
subpane_header() Children [
|
|
|
|
@ -541,7 +607,12 @@ fn primary_ui() -> impl Scene {
|
|
|
|
template_value(Note::GSharp)
|
|
|
|
template_value(Note::GSharp)
|
|
|
|
on(toggle_note),
|
|
|
|
on(toggle_note),
|
|
|
|
]
|
|
|
|
]
|
|
|
|
],
|
|
|
|
]
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn octaves() -> impl Scene {
|
|
|
|
|
|
|
|
bsn! {
|
|
|
|
subpane()
|
|
|
|
subpane()
|
|
|
|
subpane_header() Children [
|
|
|
|
subpane_header() Children [
|
|
|
|
Text("Octaves") ThemedText
|
|
|
|
Text("Octaves") ThemedText
|
|
|
|
@ -554,27 +625,42 @@ fn primary_ui() -> impl Scene {
|
|
|
|
justify_content: JustifyContent::Start,
|
|
|
|
justify_content: JustifyContent::Start,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Children [
|
|
|
|
Children [
|
|
|
|
@FeathersSlider { @max: 5., @value: 3., @min: 1. }
|
|
|
|
@FeathersSlider { @max: 11., @value: 5., @min: 1. }
|
|
|
|
SliderStep(1.)
|
|
|
|
SliderStep(2.)
|
|
|
|
SliderPrecision(0)
|
|
|
|
SliderPrecision(0)
|
|
|
|
on(|value_change: On<ValueChange<f32>>, mut pitch_map: ResMut<PitchMap>| {
|
|
|
|
on(|value_change: On<ValueChange<f32>>, mut pitch_map: ResMut<PitchMap>| {
|
|
|
|
if value_change.is_final {
|
|
|
|
if value_change.is_final {
|
|
|
|
pitch_map.octaves_up = value_change.value as usize;
|
|
|
|
pitch_map.octaves = value_change.value as usize;
|
|
|
|
debug!("(octave up) Updated pitch map: {:#?}", pitch_map);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
on(slider_self_update),
|
|
|
|
on(slider_self_update),
|
|
|
|
@FeathersSlider { @max: 5., @value: 3., @min: 1. }
|
|
|
|
]
|
|
|
|
SliderStep(1.)
|
|
|
|
|
|
|
|
SliderPrecision(0)
|
|
|
|
|
|
|
|
on(|value_change: On<ValueChange<f32>>, mut pitch_map: ResMut<PitchMap>| {
|
|
|
|
|
|
|
|
if value_change.is_final {
|
|
|
|
|
|
|
|
pitch_map.octaves_down = value_change.value as usize;
|
|
|
|
|
|
|
|
debug!("(octave down) Updated pitch map: {:#?}", pitch_map);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
on(slider_self_update),
|
|
|
|
|
|
|
|
|
|
|
|
bsn! {
|
|
|
|
|
|
|
|
Node {
|
|
|
|
|
|
|
|
display: Display::Flex,
|
|
|
|
|
|
|
|
flex_direction: FlexDirection::Column,
|
|
|
|
|
|
|
|
justify_content: JustifyContent::Start,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Transform
|
|
|
|
|
|
|
|
pane()
|
|
|
|
|
|
|
|
Children [
|
|
|
|
|
|
|
|
pane_header()
|
|
|
|
|
|
|
|
on(toggle_main_ui)
|
|
|
|
|
|
|
|
// todo: toggle main ui
|
|
|
|
|
|
|
|
Children [
|
|
|
|
|
|
|
|
Text("Conways Game of Life With Sound (click here to open control panel)") ThemedText,
|
|
|
|
],
|
|
|
|
],
|
|
|
|
|
|
|
|
pane_body()
|
|
|
|
|
|
|
|
MainUi::Visible
|
|
|
|
|
|
|
|
ToggleStateVisible
|
|
|
|
|
|
|
|
Children [
|
|
|
|
|
|
|
|
controls(),
|
|
|
|
|
|
|
|
notes(),
|
|
|
|
|
|
|
|
octaves(),
|
|
|
|
|
|
|
|
description_text(),
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -641,10 +727,10 @@ impl Coordinates {
|
|
|
|
/// For the purposes of creating assests, what does the given coordinate translate to CellPitch wise
|
|
|
|
/// For the purposes of creating assests, what does the given coordinate translate to CellPitch wise
|
|
|
|
fn to_cell_pitch(&self, pm: &PitchMap) -> CellPitch {
|
|
|
|
fn to_cell_pitch(&self, pm: &PitchMap) -> CellPitch {
|
|
|
|
let rows = pm.notes.len();
|
|
|
|
let rows = pm.notes.len();
|
|
|
|
let cols = pm.octaves_up + pm.octaves_down + 1;
|
|
|
|
let cols = pm.octaves;
|
|
|
|
|
|
|
|
|
|
|
|
let this_x = self.x.rem_euclid(rows as isize);
|
|
|
|
let this_x = self.x.rem_euclid(rows as isize);
|
|
|
|
let this_y = self.y.rem_euclid(cols as isize) - (pm.octaves_down as isize);
|
|
|
|
let this_y = self.y.rem_euclid(cols as isize) - (pm.octaves as isize / 2);
|
|
|
|
|
|
|
|
|
|
|
|
debug_assert!(this_x >= 0);
|
|
|
|
debug_assert!(this_x >= 0);
|
|
|
|
|
|
|
|
|
|
|
|
@ -1091,13 +1177,9 @@ fn load_meshes(mut cell_assets: ResMut<CellAssets>, mut meshes: ResMut<Assets<Me
|
|
|
|
|
|
|
|
|
|
|
|
fn default_board(mut writer: MessageWriter<Lifecycle>) {
|
|
|
|
fn default_board(mut writer: MessageWriter<Lifecycle>) {
|
|
|
|
// https://playgameoflife.com/lexicon/R-pentomino
|
|
|
|
// https://playgameoflife.com/lexicon/R-pentomino
|
|
|
|
[
|
|
|
|
[(0, 0), (0, -1), (-1, 0), (0, 1), (1, 1)]
|
|
|
|
(0,0),
|
|
|
|
.into_iter()
|
|
|
|
(0,-1),
|
|
|
|
.for_each(|(x, y)| {
|
|
|
|
(-1,0),
|
|
|
|
|
|
|
|
(0,1),
|
|
|
|
|
|
|
|
(1,1),
|
|
|
|
|
|
|
|
].into_iter().for_each(|(x, y)| {
|
|
|
|
|
|
|
|
writer.write(Lifecycle::Alive(Coordinates { x, y }));
|
|
|
|
writer.write(Lifecycle::Alive(Coordinates { x, y }));
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -1185,16 +1267,14 @@ fn manage_interactive<T: Component + States + PartialEq>(
|
|
|
|
#[derive(Resource, Debug)]
|
|
|
|
#[derive(Resource, Debug)]
|
|
|
|
struct PitchMap {
|
|
|
|
struct PitchMap {
|
|
|
|
notes: Vec<Note>,
|
|
|
|
notes: Vec<Note>,
|
|
|
|
octaves_up: usize,
|
|
|
|
octaves: usize,
|
|
|
|
octaves_down: usize,
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl Default for PitchMap {
|
|
|
|
impl Default for PitchMap {
|
|
|
|
fn default() -> Self {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
Self {
|
|
|
|
notes: vec![Note::A, Note::B, Note::CSharp, Note::E, Note::FSharp],
|
|
|
|
notes: vec![Note::A, Note::B, Note::CSharp, Note::E, Note::FSharp],
|
|
|
|
octaves_up: 3,
|
|
|
|
octaves: 5,
|
|
|
|
octaves_down: 3,
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -1215,8 +1295,7 @@ impl PitchMap {
|
|
|
|
fn test_cell_pitch() {
|
|
|
|
fn test_cell_pitch() {
|
|
|
|
let pm = PitchMap {
|
|
|
|
let pm = PitchMap {
|
|
|
|
notes: vec![Note::A, Note::B, Note::C],
|
|
|
|
notes: vec![Note::A, Note::B, Note::C],
|
|
|
|
octaves_up: 1,
|
|
|
|
octaves: 3,
|
|
|
|
octaves_down: 1,
|
|
|
|
|
|
|
|
};
|
|
|
|
};
|
|
|
|
let xs = -6..=5;
|
|
|
|
let xs = -6..=5;
|
|
|
|
let ys = -6..=4;
|
|
|
|
let ys = -6..=4;
|
|
|
|
@ -1335,3 +1414,41 @@ fn toggle_state_visible<S: States + Component>(
|
|
|
|
};
|
|
|
|
};
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn camera_follow(
|
|
|
|
|
|
|
|
mut camera: Query<&mut Coordinates, With<Camera>>,
|
|
|
|
|
|
|
|
cells: Query<&Coordinates, (With<Cell>, Without<Camera>)>,
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
camera.iter_mut().for_each(|mut c| {
|
|
|
|
|
|
|
|
let left = cells
|
|
|
|
|
|
|
|
.iter()
|
|
|
|
|
|
|
|
.map(|Coordinates { x, .. }| *x)
|
|
|
|
|
|
|
|
.min()
|
|
|
|
|
|
|
|
.unwrap_or(0);
|
|
|
|
|
|
|
|
let right = cells
|
|
|
|
|
|
|
|
.iter()
|
|
|
|
|
|
|
|
.map(|Coordinates { x, .. }| *x)
|
|
|
|
|
|
|
|
.max()
|
|
|
|
|
|
|
|
.unwrap_or(0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let top = cells
|
|
|
|
|
|
|
|
.iter()
|
|
|
|
|
|
|
|
.map(|Coordinates { y, .. }| *y)
|
|
|
|
|
|
|
|
.max()
|
|
|
|
|
|
|
|
.unwrap_or(0);
|
|
|
|
|
|
|
|
let bottom = cells
|
|
|
|
|
|
|
|
.iter()
|
|
|
|
|
|
|
|
.map(|Coordinates { y, .. }| *y)
|
|
|
|
|
|
|
|
.min()
|
|
|
|
|
|
|
|
.unwrap_or(0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
c.x = (right + left) / 2;
|
|
|
|
|
|
|
|
c.y = (top + bottom) / 2;
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn update_camera_position(mut query: Query<(&Coordinates, &mut Transform), With<Camera>>) {
|
|
|
|
|
|
|
|
query.iter_mut().for_each(|(c, mut t)| {
|
|
|
|
|
|
|
|
t.translation = c.as_translation();
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|