From 50d35533ccf361d2a05fda9654a5a28b2aa720f3 Mon Sep 17 00:00:00 2001 From: Elijah Voigt Date: Fri, 17 Nov 2023 21:43:29 -0800 Subject: [PATCH] Hey it worksgit add .; git commit Selection handling refactor FTW --- src/display2d.rs | 15 +++--- src/display3d.rs | 21 +++----- src/game.rs | 134 ++++++++++++++++++----------------------------- 3 files changed, 67 insertions(+), 103 deletions(-) diff --git a/src/display2d.rs b/src/display2d.rs index 9f49d1c..c5b95d9 100644 --- a/src/display2d.rs +++ b/src/display2d.rs @@ -273,6 +273,7 @@ fn select( &TextureAtlasSprite, &Handle, &GlobalTransform, + &BoardIndex, ), ( With, @@ -283,8 +284,8 @@ fn select( windows: Query<&Window, With>, cameras: Query<(&Camera, &GlobalTransform), With>, atlases: Res>, - mut commands: Commands, selected: Query, With, With)>, + mut selections: EventWriter, ) { // For each window (there is only one) windows @@ -306,6 +307,7 @@ fn select( TextureAtlasSprite { index, anchor, .. }, handle, transform, + board_index, )| { let sprite_size = atlases .get(handle) @@ -315,17 +317,16 @@ fn select( .expect("Atlas Sprite Rectangle") .size(); hit::intersects2d(sprite_size, anchor, transform, pos) - .then_some((entity, transform)) + .then_some((transform, board_index)) }, ) - .max_by(|(_, a), (_, b)| { + .max_by(|(a, _), (b, _)| { a.translation().z.partial_cmp(&b.translation().z).unwrap() }) + .map(|(_, board_index)| board_index) .iter() - .for_each(|(entity, _)| { - info!("Selected pieces: {:?}", selected.iter().len()); - assert!(selected.iter().len() <= 2, "Selected too many pieces!"); - commands.entity(*entity).insert(game::Selected); + .for_each(|&board_index| { + selections.send(game::Selection(board_index.clone())); }); }); }); diff --git a/src/display3d.rs b/src/display3d.rs index e8a3a5a..5c3c646 100644 --- a/src/display3d.rs +++ b/src/display3d.rs @@ -465,10 +465,10 @@ fn select( meshes: Res>, cameras: Query<(&Camera, &GlobalTransform)>, windows: Query<&Window, With>, - selectable: Query, With)>, + selectable: Query<(Entity, &BoardIndex), (With, With)>, children: Query<&Children>, - mut commands: Commands, selected: Query, With, With)>, + mut selections: EventWriter, ) { events .iter() @@ -487,7 +487,7 @@ fn select( hit::intersects3d(&ray, mesh, >).and_then(|_hit| { selectable .iter() - .find(|&e| { + .find_map(|(e, &board_index)| { // A child was hit (pieces) let primary = entity == e; // This entity was hit (tile hitboxes) @@ -495,19 +495,12 @@ fn select( .iter_descendants(e) .any(|child| child == entity); - primary || secondary + (primary || secondary).then_some(board_index) }) .iter() - .for_each(|&e| { - info!( - "Selected pieces: {:?}", - selected.iter().len() - ); - assert!( - selected.iter().len() <= 2, - "Selected too many pieces selected!" - ); - commands.entity(e).insert(game::Selected); + .for_each(|&board_index| { + selections + .send(game::Selection(board_index.clone())); }); Some(()) }); diff --git a/src/game.rs b/src/game.rs index 5fb139e..ae8132d 100644 --- a/src/game.rs +++ b/src/game.rs @@ -1,5 +1,6 @@ use bevy::utils::HashSet; +use crate::audio::AudioEvent; use crate::prelude::*; pub(crate) struct GamePlugin; @@ -7,23 +8,21 @@ pub(crate) struct GamePlugin; impl Plugin for GamePlugin { fn build(&self, app: &mut App) { app.add_event::() + .add_event::() .add_systems(Startup, setup_board) .add_systems( Update, ( menu::exit_to_menu.run_if(in_state(GameState::Play)), - update_board.run_if(on_event::()).after(select_sync), + update_board + .run_if(on_event::()) + .after(handle_selection), set_side.run_if(on_event::()).after(update_board), cancel_place.run_if(|buttons: Res>| -> bool { buttons.just_pressed(MouseButton::Right) }), - select_sync - .run_if(any_component_added::) - .after(deselect_sync), - deselect_sync.run_if(any_component_removed::()), - move_piece.run_if(any_component_added::), + handle_selection.run_if(on_event::()), capture_piece.run_if(any_component_added::), - null_selections.run_if(any_component_added::), pick_up_audio:: .run_if(in_state(DisplayState::Display2d)) .run_if(any_component_added::), @@ -292,6 +291,10 @@ pub(crate) struct Selected; #[derive(Debug, Default, Component)] pub(crate) struct Selectable; +/// Event for selecting board indexes for Moves +#[derive(Debug, Default, Event, Clone)] +pub(crate) struct Selection(pub BoardIndex); + fn setup_board(mut commands: Commands) { use Piece::*; commands.insert_resource(Board { @@ -347,6 +350,7 @@ fn debug_board(board: Res, mut debug_info: ResMut) { /// Update this method to use a diff between the board and the state of the 2d/3d worlds pub(crate) fn update_board( + mut audio_events: EventWriter, mut events: EventReader, mut pieces: Query<(Entity, &mut BoardIndex), With>, selected: Query>, @@ -359,6 +363,7 @@ pub(crate) fn update_board( Some(to_idx) => { info!("Moving piece {:?} to {:?}", entity, to_idx); *index = to_idx.clone(); + audio_events.send(audio::AudioEvent::PutDown); } None => { info!("Capturing piece {:?}", entity); @@ -391,73 +396,58 @@ pub(crate) fn set_side(mut events: Query<(&mut Side, &BoardIndex), Changed>, - pieces: Query<(Entity, &BoardIndex), (With, With)>, - mut commands: Commands, -) { - events.iter().for_each(|entity| { - if let Ok((this_e, this_idx)) = pieces.get(entity) { - if let Some((entangled, _)) = pieces - .iter() - .find(|(e, idx)| *idx == this_idx && *e != this_e) - { - commands.entity(entangled).insert(Selected); - } - } - }) -} - -fn deselect_sync( - mut events: RemovedComponents, - pieces: Query<(Entity, &BoardIndex), (With, With)>, +// TODO: Handle 3d Pickup (Not showing hover animation, but still selected?) +// TODO: Handle cancel move (currently 2d just drops it in place) +fn handle_selection( + mut selections: EventReader, + mut move_events: EventWriter, + selected: Query<(Entity, &BoardIndex), (With, With)>, + pieces: Query<(Entity, &BoardIndex), (With, Without, With)>, + tiles: Query<(Entity, &BoardIndex), (With, With)>, + mut board: ResMut, mut commands: Commands, ) { - events.iter().for_each(|entity| { - if let Ok((this_e, this_idx)) = pieces.get(entity) { - if let Some((entangled, _)) = pieces + selections.iter().for_each(|Selection(index)| { + // There are no currently selected entities + // Mark the piece at this index as selected + if selected.is_empty() { + pieces .iter() - .find(|(e, idx)| *idx == this_idx && *e != this_e) - { - info!("De-selecting entangled piece {:?}", entity); - commands.entity(entangled).remove::(); - } + .filter(|(this, this_index)| *this_index == index) + .for_each(|(piece, piece_index)| { + info!("Selecting {:?} at {:?}", piece, piece_index); + commands.entity(piece).insert(Selected); + }); } - }) -} - -/// Triggered when right-mouse-button clicked -fn cancel_place(current: Query>, mut commands: Commands) { - current.iter().for_each(|entity| { - info!("De-selecting {:?}", entity); - commands.entity(entity).remove::(); - }); -} - -/// When a tile is selected, move all selected pieces to that index -fn move_piece( - events: Query<&BoardIndex, (With, Added)>, - selected_pieces: Query<&BoardIndex, (With, With)>, - mut board: ResMut, - mut move_events: EventWriter, - mut writer: EventWriter, -) { - events.iter().for_each(|to| { - selected_pieces.iter().for_each(|from| { - if from != to { - info!("Applying move {:?} -> {:?}", from, to); - // Move piece - match board.move_piece(*from, *to) { + // There is a currently selected entity, so submit moves + else { + assert!( + selected.iter().len() <= 2, + "There are too many pieces selected!" + ); + selected.iter().for_each(|(current, current_index)| { + match board.move_piece(*current_index, *index) { Ok(moves) => { // De-select the piece info!("Applying moves {:?}", moves); moves.iter().for_each(|m| move_events.send(m.clone())); - writer.send(audio::AudioEvent::PutDown) } Err(GameError::NullMove) => warn!("Null move!"), Err(GameError::InvalidIndex) => warn!("Invalid index!"), } - } + }); + } + }); +} + +/// Triggered when right-mouse-button clicked +fn cancel_place(current: Query<&BoardIndex, With>, mut events: EventWriter) { + current.iter().for_each(|board_index| { + info!("De-selecting piece at {:?}", board_index); + events.send(Move { + from: board_index.clone(), + to: Some(board_index.clone()), + ..default() }); }); } @@ -471,26 +461,6 @@ fn pick_up_audio( } } -/// De-select anything that shouldn't be selected -/// Namely tiles when there are not selected pieces -fn null_selections( - events: Query>, - selected_pieces: Query, With)>, - mut commands: Commands, - mut writer: EventWriter, -) { - events.iter().for_each(|entity| { - if selected_pieces.is_empty() { - info!( - "De-selecting piece that should not be selected {:?}", - entity - ); - commands.entity(entity).remove::(); - writer.send(audio::AudioEvent::PutDown); - } - }); -} - /// When a piece's _BoardIndex_ is removed, we hide that entity from the viewer fn capture_piece(mut events: Query<&mut Visibility, Added>) { events.iter_mut().for_each(|mut vis| {