Hey it worksgit add .; git commit Selection handling refactor FTW

bevy0.12
Elijah Voigt 2 years ago
parent 12bf2ea96d
commit 50d35533cc

@ -273,6 +273,7 @@ fn select(
&TextureAtlasSprite, &TextureAtlasSprite,
&Handle<TextureAtlas>, &Handle<TextureAtlas>,
&GlobalTransform, &GlobalTransform,
&BoardIndex,
), ),
( (
With<game::Selectable>, With<game::Selectable>,
@ -283,8 +284,8 @@ fn select(
windows: Query<&Window, With<PrimaryWindow>>, windows: Query<&Window, With<PrimaryWindow>>,
cameras: Query<(&Camera, &GlobalTransform), With<Display2d>>, cameras: Query<(&Camera, &GlobalTransform), With<Display2d>>,
atlases: Res<Assets<TextureAtlas>>, atlases: Res<Assets<TextureAtlas>>,
mut commands: Commands,
selected: Query<Entity, (With<game::Selected>, With<game::Piece>, With<Display2d>)>, selected: Query<Entity, (With<game::Selected>, With<game::Piece>, With<Display2d>)>,
mut selections: EventWriter<game::Selection>,
) { ) {
// For each window (there is only one) // For each window (there is only one)
windows windows
@ -306,6 +307,7 @@ fn select(
TextureAtlasSprite { index, anchor, .. }, TextureAtlasSprite { index, anchor, .. },
handle, handle,
transform, transform,
board_index,
)| { )| {
let sprite_size = atlases let sprite_size = atlases
.get(handle) .get(handle)
@ -315,17 +317,16 @@ fn select(
.expect("Atlas Sprite Rectangle") .expect("Atlas Sprite Rectangle")
.size(); .size();
hit::intersects2d(sprite_size, anchor, transform, pos) 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() a.translation().z.partial_cmp(&b.translation().z).unwrap()
}) })
.map(|(_, board_index)| board_index)
.iter() .iter()
.for_each(|(entity, _)| { .for_each(|&board_index| {
info!("Selected pieces: {:?}", selected.iter().len()); selections.send(game::Selection(board_index.clone()));
assert!(selected.iter().len() <= 2, "Selected too many pieces!");
commands.entity(*entity).insert(game::Selected);
}); });
}); });
}); });

@ -465,10 +465,10 @@ fn select(
meshes: Res<Assets<Mesh>>, meshes: Res<Assets<Mesh>>,
cameras: Query<(&Camera, &GlobalTransform)>, cameras: Query<(&Camera, &GlobalTransform)>,
windows: Query<&Window, With<PrimaryWindow>>, windows: Query<&Window, With<PrimaryWindow>>,
selectable: Query<Entity, (With<game::Selectable>, With<Display3d>)>, selectable: Query<(Entity, &BoardIndex), (With<game::Selectable>, With<Display3d>)>,
children: Query<&Children>, children: Query<&Children>,
mut commands: Commands,
selected: Query<Entity, (With<game::Selected>, With<game::Piece>, With<Display3d>)>, selected: Query<Entity, (With<game::Selected>, With<game::Piece>, With<Display3d>)>,
mut selections: EventWriter<game::Selection>,
) { ) {
events events
.iter() .iter()
@ -487,7 +487,7 @@ fn select(
hit::intersects3d(&ray, mesh, &gt).and_then(|_hit| { hit::intersects3d(&ray, mesh, &gt).and_then(|_hit| {
selectable selectable
.iter() .iter()
.find(|&e| { .find_map(|(e, &board_index)| {
// A child was hit (pieces) // A child was hit (pieces)
let primary = entity == e; let primary = entity == e;
// This entity was hit (tile hitboxes) // This entity was hit (tile hitboxes)
@ -495,19 +495,12 @@ fn select(
.iter_descendants(e) .iter_descendants(e)
.any(|child| child == entity); .any(|child| child == entity);
primary || secondary (primary || secondary).then_some(board_index)
}) })
.iter() .iter()
.for_each(|&e| { .for_each(|&board_index| {
info!( selections
"Selected pieces: {:?}", .send(game::Selection(board_index.clone()));
selected.iter().len()
);
assert!(
selected.iter().len() <= 2,
"Selected too many pieces selected!"
);
commands.entity(e).insert(game::Selected);
}); });
Some(()) Some(())
}); });

@ -1,5 +1,6 @@
use bevy::utils::HashSet; use bevy::utils::HashSet;
use crate::audio::AudioEvent;
use crate::prelude::*; use crate::prelude::*;
pub(crate) struct GamePlugin; pub(crate) struct GamePlugin;
@ -7,23 +8,21 @@ pub(crate) struct GamePlugin;
impl Plugin for GamePlugin { impl Plugin for GamePlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.add_event::<Move>() app.add_event::<Move>()
.add_event::<Selection>()
.add_systems(Startup, setup_board) .add_systems(Startup, setup_board)
.add_systems( .add_systems(
Update, Update,
( (
menu::exit_to_menu.run_if(in_state(GameState::Play)), menu::exit_to_menu.run_if(in_state(GameState::Play)),
update_board.run_if(on_event::<Move>()).after(select_sync), update_board
.run_if(on_event::<Move>())
.after(handle_selection),
set_side.run_if(on_event::<Move>()).after(update_board), set_side.run_if(on_event::<Move>()).after(update_board),
cancel_place.run_if(|buttons: Res<Input<MouseButton>>| -> bool { cancel_place.run_if(|buttons: Res<Input<MouseButton>>| -> bool {
buttons.just_pressed(MouseButton::Right) buttons.just_pressed(MouseButton::Right)
}), }),
select_sync handle_selection.run_if(on_event::<Selection>()),
.run_if(any_component_added::<Selected>)
.after(deselect_sync),
deselect_sync.run_if(any_component_removed::<Selected>()),
move_piece.run_if(any_component_added::<Selected>),
capture_piece.run_if(any_component_added::<Captured>), capture_piece.run_if(any_component_added::<Captured>),
null_selections.run_if(any_component_added::<Selected>),
pick_up_audio::<display2d::Display2d> pick_up_audio::<display2d::Display2d>
.run_if(in_state(DisplayState::Display2d)) .run_if(in_state(DisplayState::Display2d))
.run_if(any_component_added::<Selected>), .run_if(any_component_added::<Selected>),
@ -292,6 +291,10 @@ pub(crate) struct Selected;
#[derive(Debug, Default, Component)] #[derive(Debug, Default, Component)]
pub(crate) struct Selectable; 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) { fn setup_board(mut commands: Commands) {
use Piece::*; use Piece::*;
commands.insert_resource(Board { commands.insert_resource(Board {
@ -347,6 +350,7 @@ fn debug_board(board: Res<Board>, mut debug_info: ResMut<debug::DebugInfo>) {
/// Update this method to use a diff between the board and the state of the 2d/3d worlds /// Update this method to use a diff between the board and the state of the 2d/3d worlds
pub(crate) fn update_board( pub(crate) fn update_board(
mut audio_events: EventWriter<AudioEvent>,
mut events: EventReader<Move>, mut events: EventReader<Move>,
mut pieces: Query<(Entity, &mut BoardIndex), With<Piece>>, mut pieces: Query<(Entity, &mut BoardIndex), With<Piece>>,
selected: Query<Entity, With<Selected>>, selected: Query<Entity, With<Selected>>,
@ -359,6 +363,7 @@ pub(crate) fn update_board(
Some(to_idx) => { Some(to_idx) => {
info!("Moving piece {:?} to {:?}", entity, to_idx); info!("Moving piece {:?} to {:?}", entity, to_idx);
*index = to_idx.clone(); *index = to_idx.clone();
audio_events.send(audio::AudioEvent::PutDown);
} }
None => { None => {
info!("Capturing piece {:?}", entity); info!("Capturing piece {:?}", entity);
@ -391,74 +396,59 @@ pub(crate) fn set_side(mut events: Query<(&mut Side, &BoardIndex), Changed<Board
}); });
} }
fn select_sync( // TODO: Handle 3d Pickup (Not showing hover animation, but still selected?)
events: Query<Entity, Added<Selected>>, // TODO: Handle cancel move (currently 2d just drops it in place)
pieces: Query<(Entity, &BoardIndex), (With<Selectable>, With<Piece>)>, fn handle_selection(
mut commands: Commands, mut selections: EventReader<Selection>,
) { mut move_events: EventWriter<Move>,
events.iter().for_each(|entity| { selected: Query<(Entity, &BoardIndex), (With<Selected>, With<Piece>)>,
if let Ok((this_e, this_idx)) = pieces.get(entity) { pieces: Query<(Entity, &BoardIndex), (With<Selectable>, Without<Selected>, With<Piece>)>,
if let Some((entangled, _)) = pieces tiles: Query<(Entity, &BoardIndex), (With<Selectable>, With<Tile>)>,
.iter() mut board: ResMut<Board>,
.find(|(e, idx)| *idx == this_idx && *e != this_e)
{
commands.entity(entangled).insert(Selected);
}
}
})
}
fn deselect_sync(
mut events: RemovedComponents<Selected>,
pieces: Query<(Entity, &BoardIndex), (With<Selectable>, With<Piece>)>,
mut commands: Commands, mut commands: Commands,
) { ) {
events.iter().for_each(|entity| { selections.iter().for_each(|Selection(index)| {
if let Ok((this_e, this_idx)) = pieces.get(entity) { // There are no currently selected entities
if let Some((entangled, _)) = pieces // Mark the piece at this index as selected
if selected.is_empty() {
pieces
.iter() .iter()
.find(|(e, idx)| *idx == this_idx && *e != this_e) .filter(|(this, this_index)| *this_index == index)
{ .for_each(|(piece, piece_index)| {
info!("De-selecting entangled piece {:?}", entity); info!("Selecting {:?} at {:?}", piece, piece_index);
commands.entity(entangled).remove::<Selected>(); commands.entity(piece).insert(Selected);
}
}
})
}
/// Triggered when right-mouse-button clicked
fn cancel_place(current: Query<Entity, With<Selected>>, mut commands: Commands) {
current.iter().for_each(|entity| {
info!("De-selecting {:?}", entity);
commands.entity(entity).remove::<Selected>();
}); });
} }
// There is a currently selected entity, so submit moves
/// When a tile is selected, move all selected pieces to that index else {
fn move_piece( assert!(
events: Query<&BoardIndex, (With<BoardIndex>, Added<Selected>)>, selected.iter().len() <= 2,
selected_pieces: Query<&BoardIndex, (With<Selected>, With<Piece>)>, "There are too many pieces selected!"
mut board: ResMut<Board>, );
mut move_events: EventWriter<Move>, selected.iter().for_each(|(current, current_index)| {
mut writer: EventWriter<audio::AudioEvent>, match board.move_piece(*current_index, *index) {
) {
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) {
Ok(moves) => { Ok(moves) => {
// De-select the piece // De-select the piece
info!("Applying moves {:?}", moves); info!("Applying moves {:?}", moves);
moves.iter().for_each(|m| move_events.send(m.clone())); moves.iter().for_each(|m| move_events.send(m.clone()));
writer.send(audio::AudioEvent::PutDown)
} }
Err(GameError::NullMove) => warn!("Null move!"), Err(GameError::NullMove) => warn!("Null move!"),
Err(GameError::InvalidIndex) => warn!("Invalid index!"), Err(GameError::InvalidIndex) => warn!("Invalid index!"),
} }
});
} }
}); });
}
/// Triggered when right-mouse-button clicked
fn cancel_place(current: Query<&BoardIndex, With<Selected>>, mut events: EventWriter<Move>) {
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<D: Component>(
} }
} }
/// De-select anything that shouldn't be selected
/// Namely tiles when there are not selected pieces
fn null_selections(
events: Query<Entity, Added<Selected>>,
selected_pieces: Query<Entity, (With<Selected>, With<Piece>)>,
mut commands: Commands,
mut writer: EventWriter<audio::AudioEvent>,
) {
events.iter().for_each(|entity| {
if selected_pieces.is_empty() {
info!(
"De-selecting piece that should not be selected {:?}",
entity
);
commands.entity(entity).remove::<Selected>();
writer.send(audio::AudioEvent::PutDown);
}
});
}
/// When a piece's _BoardIndex_ is removed, we hide that entity from the viewer /// When a piece's _BoardIndex_ is removed, we hide that entity from the viewer
fn capture_piece(mut events: Query<&mut Visibility, Added<Captured>>) { fn capture_piece(mut events: Query<&mut Visibility, Added<Captured>>) {
events.iter_mut().for_each(|mut vis| { events.iter_mut().for_each(|mut vis| {

Loading…
Cancel
Save