diff --git a/assets/martian.tweak.toml b/assets/martian.tweak.toml index f1af478..94c6522 100644 --- a/assets/martian.tweak.toml +++ b/assets/martian.tweak.toml @@ -33,7 +33,7 @@ invalid = "/sfx/3D/3DInvalidMove" # Options: Off, Sample2, Sample4, Sample8 # Requires: display3d.ssoa.quality_level = "Off" ### -msaa = "Off" +msaa = "Sample4" ### # Enable HDR lighting @@ -62,8 +62,8 @@ valid_move = "Valid Move Spot" [display3d.models.animations] intro_a = "GameCamIntro1" intro_b = "GameCamIntro2" -turn_a = "GameCamSide2>1" -turn_b = "GameCamSide1>2" +turn_b = "GameCamSide2>1" +turn_a = "GameCamSide1>2" [display3d.models.animations.pick_up] pawn = "PawnPiecePickup" @@ -113,7 +113,7 @@ Rgba = { red = 1.0, green = 1.0, blue = 1.0, alpha = 0.0 } # https://docs.rs/bevy/0.11.3/bevy/pbr/enum.FogFalloff.html ### [display3d.fog.falloff] -Exponential = { density = 0.000 } +Exponential = { density = 1.0 } # Examples: # * Linear = { start = 1.0, end = 10.0 } # * Exponential = { density = 1.0 } diff --git a/src/audio.rs b/src/audio.rs index 3c1c431..1cb1e2b 100644 --- a/src/audio.rs +++ b/src/audio.rs @@ -36,7 +36,7 @@ impl Plugin for AudioPlugin { #[derive(Event, Debug, PartialEq, Component, Clone)] pub enum AudioEvent { MainMusic, - StopMainMusic, + _StopMainMusic, MenuHover, MenuSelect, PickUp, @@ -56,7 +56,7 @@ fn play_audio(mut events: Query<&AudioSource, Added>) { fn audio_trigger( mut events: EventReader, - sources: Query<(&AudioSource, &AudioEvent)>, + sources: Query<(Entity, &AudioSource, &AudioEvent)>, studio: Res, mut commands: Commands, server: Res, @@ -69,7 +69,7 @@ fn audio_trigger( let state = display_state.get(); events.read().for_each(|event| { let aud = match event { - AudioEvent::MainMusic | AudioEvent::StopMainMusic => { + AudioEvent::MainMusic | AudioEvent::_StopMainMusic => { tweak.get::("audio_music_main").unwrap() } AudioEvent::MenuHover => tweak.get::("audio_menu_hover").unwrap(), @@ -79,7 +79,7 @@ fn audio_trigger( AudioEvent::Idle | AudioEvent::StopIdle => tweak.get::("audio_display3d_idle").unwrap(), AudioEvent::Invalid => tweak.get::("audio_display3d_invalid").unwrap(), }; - // There is an event for this + // There is an event, play an audio if !aud.is_empty() { let event_str = format!("event:{}", aud); if let Ok(event_description) = studio.0.get_event(event_str.as_str()) { @@ -90,25 +90,28 @@ fn audio_trigger( AudioEvent::StopIdle => { sources .iter() - .filter(|(_, source_event)| **source_event == AudioEvent::Idle) - .for_each(|(source, _)| { + .filter(|(_, _, source_event)| **source_event == AudioEvent::Idle) + .for_each(|(entity, source, _)| { info!("Stopping audio {}", event_str); source.stop(); + commands.entity(entity).despawn_recursive(); }); } // Find and stop playing instances of main music - AudioEvent::StopMainMusic => { + AudioEvent::_StopMainMusic => { sources .iter() - .filter(|(_, source_event)| **source_event == AudioEvent::MainMusic) - .for_each(|(source, _)| { + .filter(|(_, _, source_event)| **source_event == AudioEvent::MainMusic) + .for_each(|(entity, source, _)| { info!("Stopping audio {}", event_str); source.stop(); + commands.entity(entity).despawn_recursive(); }); } // we are playing a sound _ => { info!("Playing audio {}", event_str); + // TODO: Can we batch spawn all sounds at startup? Then Start/Stop/Reset at runtime? commands.spawn((audio_source, event.clone())); } } diff --git a/src/display3d.rs b/src/display3d.rs index 82fd9e2..f8b4942 100644 --- a/src/display3d.rs +++ b/src/display3d.rs @@ -32,7 +32,7 @@ impl Plugin for Display3dPlugin { .insert_resource(Msaa::Off) .add_systems( OnExit(GameState::Loading), - (initialize, fix_skybox.before(initialize)), + (initialize, fix_skybox.before(initialize), update_tweaks.run_if(resource_exists::()),), ) .add_systems( Update, @@ -44,9 +44,10 @@ impl Plugin for Display3dPlugin { set_piece_model.run_if(any_component_added::), set_board_model.run_if(any_component_added::), set_board_model.run_if(any_component_added::), + set_valid_move_model.run_if(any_component_added::), set_tile_hitbox.run_if(any_component_added::), set_piece_position.run_if(any_component_changed::), - set_piece_texture.run_if(any_component_changed::), + set_piece_texture.run_if(any_component_changed::).run_if(resource_exists::()), select .run_if(in_state(GameState::Play)) .run_if(in_state(DisplayState::Display3d)) @@ -56,8 +57,7 @@ impl Plugin for Display3dPlugin { switch_sides .run_if(in_state(GameState::Play)) .run_if(state_changed::()), - set_valid_move_model.run_if(any_component_added::), - update_tweaks.run_if(on_event::>()), + update_tweaks.run_if(on_event::>()).run_if(resource_exists::()), scale_lighting.run_if( any_component_added:: .or_else(any_component_added::) @@ -84,11 +84,10 @@ impl Plugin for Display3dPlugin { OnEnter(DisplayState::Display3d), ( activate::, - set_piece_texture, + set_piece_texture.run_if(resource_exists::()), opening_animation .run_if(run_once()) .run_if(in_state(GameState::Play)), - update_tweaks, ), ) .add_systems(OnExit(DisplayState::Display3d), deactivate::) @@ -97,6 +96,7 @@ impl Plugin for Display3dPlugin { ( activate::.run_if(in_state(DisplayState::Display3d)), set_piece_texture, + update_tweaks.run_if(resource_exists::()), opening_animation .run_if(run_once()) .run_if(in_state(DisplayState::Display3d)), @@ -160,6 +160,8 @@ fn initialize(mut commands: Commands, board: Res, assets: Res, assets: Res, assets: Res("display3d_hdr").unwrap(), ..default() }, @@ -732,9 +738,10 @@ fn select( meshes: Res>, cameras: Query<(&Camera, &GlobalTransform)>, windows: Query<&Window, With>, - selectable: Query<(Entity, &BoardIndex), (With, With)>, + selectable: Query<(Entity, &BoardIndex, &Side, Option<&Piece>), (With, With)>, children: Query<&Children>, mut selections: EventWriter, + state: Res>, ) { events .read() @@ -753,15 +760,20 @@ fn select( hit::intersects3d(&ray, mesh, >).and_then(|_hit| { selectable .iter() - .find_map(|(e, &board_index)| { - // A child was hit (pieces) - let primary = entity == e; + .find_map(|(e, &board_index, &side, piece_ish)| { + // Check if this piece is on the active side + let side_check = piece_ish.is_some() && *state.get() == side; + // This entity was hit (tile hitboxes) + let primary = entity == e; + + // A child was hit (pieces) let secondary = children .iter_descendants(e) .any(|child| child == entity); - (primary || secondary).then_some(board_index) + (side_check && (primary || secondary)).then_some(board_index) + }) .iter() .for_each(|&board_index| { @@ -804,7 +816,7 @@ fn moves_gizmo( } fn set_valid_move_model( - mut events: Query<&mut Handle, (With, Added)>, + mut events: Query<(&mut Handle, &mut Visibility), (With, Added)>, gltfs: Res>, tweaks: Res>, tweaks_file: Res, @@ -816,7 +828,7 @@ fn set_valid_move_model( .get_handle::("display3d_models_assets_file") .unwrap(); if let Some(gltf) = gltfs.get(assets_handle) { - events.iter_mut().for_each(|mut handle| { + events.iter_mut().for_each(|(mut handle, mut visibility)| { *handle = gltf .named_scenes .get( @@ -826,7 +838,9 @@ fn set_valid_move_model( .as_str(), ) .unwrap() - .clone() + .clone(); + + *visibility = Visibility::Hidden; }) } } diff --git a/src/game.rs b/src/game.rs index 7d12863..b1f72d6 100644 --- a/src/game.rs +++ b/src/game.rs @@ -12,6 +12,7 @@ impl Plugin for GamePlugin { .add_state::() .insert_resource(Score { ..default() }) .add_systems(Startup, setup_board) + .add_systems(OnEnter(GameState::Play), hide_valid_moves) .add_systems( Update, ( @@ -24,9 +25,6 @@ impl Plugin for GamePlugin { buttons.just_pressed(MouseButton::Right) }), handle_selection.run_if(on_event::()), - switch_sides.run_if(|input: Res>| -> bool { - input.just_pressed(KeyCode::N) - }), show_valid_moves.run_if(any_component_added::), hide_valid_moves.run_if(any_component_removed::()), manage_score.run_if(any_component_added::), @@ -45,11 +43,34 @@ impl Plugin for GamePlugin { #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default, States)] pub(crate) enum TurnState { - #[default] SideA, + // HACK: Opening animation starts on B side + #[default] SideB, } +impl std::ops::Not for TurnState { + type Output = Self; + + fn not(self) -> Self::Output { + match self { + TurnState::SideA => TurnState::SideB, + TurnState::SideB => TurnState::SideA, + } + } +} + +// Allow comparison between turn state and sides +impl PartialEq for TurnState { + fn eq(&self, other: &Side) -> bool { + match (self, other) { + (TurnState::SideA, Side::A) | (TurnState::SideB, Side::B) => true, + (TurnState::SideB, Side::A) | (TurnState::SideA, Side::B) => false, + } + } +} + + #[derive(Debug, Component, Clone, PartialEq, Copy, Hash)] pub(crate) enum Piece { Pawn, @@ -481,18 +502,25 @@ pub(crate) fn update_board( selected: Query>, mut commands: Commands, mut played: Local, + curr_state: Res>, + mut next_state: ResMut>, ) { events.read().for_each(|Move { from, to, .. }| { pieces.iter_mut().for_each(|(entity, mut index)| { if *index == *from { match to { Some(to_idx) => { - info!("Moving piece {:?} to {:?}", entity, to_idx); + info!("Moving piece {:?} {:?} -> {:?}", entity, from, to_idx); *index = to_idx.clone(); if !(*played) { audio_events.send(audio::AudioEvent::PutDown); audio_events.send(audio::AudioEvent::StopIdle); *played = true; + if *from != *to_idx { + let ns = !*curr_state.get() ; + info!("Piece moved, switching sides: {:?}", ns); + next_state.set(ns); + } } } None => { @@ -650,26 +678,19 @@ fn asserts( } } -fn switch_sides(state: Res>, mut next: ResMut>) { - match state.get() { - TurnState::SideA => next.set(TurnState::SideB), - TurnState::SideB => next.set(TurnState::SideA), - } -} - /// Spawn "Valid move" indicators when a piece is selected /// Another system registers these new entities and associates the correct models and plays animations. fn show_valid_moves( events: Query<&BoardIndex, (With, Added)>, board: Res, - mut valid_moves: Query<(&BoardIndex, &mut Visibility), With>, + mut indicators: Query<(&BoardIndex, &mut Visibility), With>, ) { // When a piece is selected events.iter().for_each(|idx| { // Iterate over all ValidMove entities // For each one with a ValidMove index, make it visible board.valid_moves(*idx).iter().for_each(|idx| { - valid_moves.iter_mut().for_each(|(i, mut vis)| { + indicators.iter_mut().for_each(|(i, mut vis)| { if i == idx { *vis = Visibility::Inherited; } @@ -680,12 +701,9 @@ fn show_valid_moves( /// Hide "Valid Move" indicators when a piece is de-selected fn hide_valid_moves( - mut events: RemovedComponents, - mut valid_moves: Query<&mut Visibility, With>, + mut indicators: Query<&mut Visibility, With>, ) { - events.read().for_each(|_| { - valid_moves.iter_mut().for_each(|mut visibility| { - *visibility = Visibility::Hidden; - }); + indicators.iter_mut().for_each(|mut visibility| { + *visibility = Visibility::Hidden; }); -} +} \ No newline at end of file diff --git a/src/hit.rs b/src/hit.rs index 3dd7032..15fabe7 100644 --- a/src/hit.rs +++ b/src/hit.rs @@ -1,8 +1,6 @@ -use bevy::{ - render::{ - mesh::{MeshVertexAttribute, VertexAttributeValues}, - render_resource::VertexFormat, - }, +use bevy::render::{ + mesh::{MeshVertexAttribute, VertexAttributeValues}, + render_resource::VertexFormat, }; use crate::prelude::*; diff --git a/src/main.rs b/src/main.rs index c773d2e..457d977 100644 --- a/src/main.rs +++ b/src/main.rs @@ -101,7 +101,7 @@ fn toggle_display_camera( } fn activate( - mut entities: Query<&mut Visibility, (With, Without)>, + mut entities: Query<&mut Visibility, (With, Without, Without)>, ) { entities.iter_mut().for_each(|mut visibility| { *visibility = Visibility::Visible; diff --git a/src/menu.rs b/src/menu.rs index 0376284..631b198 100644 --- a/src/menu.rs +++ b/src/menu.rs @@ -50,6 +50,16 @@ fn init_menu_ui(mut commands: Commands) { }, )) .with_children(|parent| { + parent.spawn( + TextBundle::from_section( + "M A R T I A N C H E S S", + TextStyle { + font_size: 48.0, + color: Color::ORANGE_RED, + ..default() + }, + ) + ); parent .spawn(( GameState::Play,