|
|
|
@ -558,49 +558,72 @@ fn select(
|
|
|
|
mut selections: EventWriter<game::Selection>,
|
|
|
|
mut selections: EventWriter<game::Selection>,
|
|
|
|
state: Res<State<game::TurnState>>,
|
|
|
|
state: Res<State<game::TurnState>>,
|
|
|
|
) {
|
|
|
|
) {
|
|
|
|
|
|
|
|
// For every mouse click event
|
|
|
|
events
|
|
|
|
events
|
|
|
|
.read()
|
|
|
|
.read()
|
|
|
|
|
|
|
|
// Only read button presses
|
|
|
|
.filter(|ev| ev.state == ButtonState::Pressed)
|
|
|
|
.filter(|ev| ev.state == ButtonState::Pressed)
|
|
|
|
.for_each(|_| {
|
|
|
|
.for_each(|_| {
|
|
|
|
|
|
|
|
// For each window (there should be only one)
|
|
|
|
windows.iter().for_each(|window| {
|
|
|
|
windows.iter().for_each(|window| {
|
|
|
|
|
|
|
|
// Get the cursor position
|
|
|
|
if let Some(pos) = window.cursor_position() {
|
|
|
|
if let Some(pos) = window.cursor_position() {
|
|
|
|
|
|
|
|
// iterate over every camera
|
|
|
|
cameras.iter().for_each(|(camera, gt)| {
|
|
|
|
cameras.iter().for_each(|(camera, gt)| {
|
|
|
|
|
|
|
|
// Get a ray from the camera through the cursor into the world
|
|
|
|
if let Some(ray) = camera.viewport_to_world(gt, pos) {
|
|
|
|
if let Some(ray) = camera.viewport_to_world(gt, pos) {
|
|
|
|
|
|
|
|
// Iterate over every entity with a 3d scene
|
|
|
|
query
|
|
|
|
query
|
|
|
|
.iter()
|
|
|
|
.iter()
|
|
|
|
|
|
|
|
// Transform the scene handle into mesh data
|
|
|
|
.filter_map(|(entity, handle, gt)| {
|
|
|
|
.filter_map(|(entity, handle, gt)| {
|
|
|
|
meshes.get(handle).map(|mesh| (entity, mesh, gt))
|
|
|
|
meshes.get(handle).map(|mesh| (entity, mesh, gt))
|
|
|
|
})
|
|
|
|
})
|
|
|
|
.for_each(|(entity, mesh, gt)| {
|
|
|
|
// Iterate over every mesh + global transform
|
|
|
|
if let Some(_hit) = hit::intersects3d(&ray, mesh, gt) {
|
|
|
|
.filter_map(|(entity, mesh, gt)| {
|
|
|
|
selectable
|
|
|
|
// If the camera -> cursor -> * ray intersects with the mesh
|
|
|
|
.iter()
|
|
|
|
hit3d::intersects3d(&ray, mesh, gt).map(|hit| (entity, hit))
|
|
|
|
.find_map(|(e, &board_index, &side)| {
|
|
|
|
})
|
|
|
|
// Check the side of the selection if no piece is selected
|
|
|
|
.filter_map(|(entity, hit)| {
|
|
|
|
// Otherwise this is fine, select away
|
|
|
|
// Find this entity in the set of selectable entities
|
|
|
|
let side_check =
|
|
|
|
selectable
|
|
|
|
!selected.is_empty() || state.get().0 == side;
|
|
|
|
.iter()
|
|
|
|
|
|
|
|
.find_map(|(e, &board_index, &side)| {
|
|
|
|
let hit_check = {
|
|
|
|
// Check the side of the selection if no piece is selected
|
|
|
|
// This entity was hit (tile hitboxes)
|
|
|
|
// Otherwise this is fine, select away
|
|
|
|
let primary = entity == e;
|
|
|
|
let side_check =
|
|
|
|
|
|
|
|
!selected.is_empty() || state.get().0 == side;
|
|
|
|
// A child was hit (pieces)
|
|
|
|
|
|
|
|
let secondary = children
|
|
|
|
let hit_check = {
|
|
|
|
.iter_descendants(e)
|
|
|
|
// This entity was hit (tile hitboxes)
|
|
|
|
.any(|child| child == entity);
|
|
|
|
let primary = entity == e;
|
|
|
|
|
|
|
|
|
|
|
|
primary || secondary
|
|
|
|
// A child was hit (pieces)
|
|
|
|
};
|
|
|
|
let secondary = children
|
|
|
|
|
|
|
|
.iter_descendants(e)
|
|
|
|
(side_check && hit_check).then_some(board_index)
|
|
|
|
.any(|child| child == entity);
|
|
|
|
})
|
|
|
|
|
|
|
|
.iter()
|
|
|
|
primary || secondary
|
|
|
|
.for_each(|&board_index| {
|
|
|
|
};
|
|
|
|
info!("Board index selected: {:?}", board_index);
|
|
|
|
|
|
|
|
selections.send(game::Selection(board_index));
|
|
|
|
// Return the board index of this piece
|
|
|
|
});
|
|
|
|
(side_check && hit_check).then_some(board_index)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
.map(|board_index| {
|
|
|
|
|
|
|
|
// Include the hit from the camera
|
|
|
|
|
|
|
|
(hit, board_index)
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
// Compare the distance of all hits, choosing the closest one
|
|
|
|
|
|
|
|
.min_by(|(hit_a, _), (hit_b, _)| {
|
|
|
|
|
|
|
|
hit_a.distance.partial_cmp(&hit_b.distance).unwrap()
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
// Iterate over the 0 or 1 outcomes of the above
|
|
|
|
|
|
|
|
.iter()
|
|
|
|
|
|
|
|
// Send an event that this board index was selected
|
|
|
|
|
|
|
|
.for_each(|(_, board_index)| {
|
|
|
|
|
|
|
|
info!("Board index selected: {:?}", board_index);
|
|
|
|
|
|
|
|
selections.send(game::Selection(*board_index));
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|