|
|
|
@ -13,6 +13,7 @@ impl Plugin for Display3dPlugin {
|
|
|
|
MaterialPlugin::<DissolveMaterial>::default(),
|
|
|
|
MaterialPlugin::<DissolveMaterial>::default(),
|
|
|
|
))
|
|
|
|
))
|
|
|
|
.init_state::<DissolvingAnimation>()
|
|
|
|
.init_state::<DissolvingAnimation>()
|
|
|
|
|
|
|
|
.init_resource::<PiecePointer>()
|
|
|
|
.insert_resource(Msaa::Off)
|
|
|
|
.insert_resource(Msaa::Off)
|
|
|
|
.insert_resource(AmbientLight {
|
|
|
|
.insert_resource(AmbientLight {
|
|
|
|
color: Color::WHITE,
|
|
|
|
color: Color::WHITE,
|
|
|
|
@ -69,6 +70,16 @@ impl Plugin for Display3dPlugin {
|
|
|
|
set_title_model.run_if(any_component_added::<TitleText>()),
|
|
|
|
set_title_model.run_if(any_component_added::<TitleText>()),
|
|
|
|
set_valid_move_model.run_if(any_component_added::<game::ValidMove>()),
|
|
|
|
set_valid_move_model.run_if(any_component_added::<game::ValidMove>()),
|
|
|
|
set_tile_hitbox.run_if(any_component_added::<game::Tile>()),
|
|
|
|
set_tile_hitbox.run_if(any_component_added::<game::Tile>()),
|
|
|
|
|
|
|
|
entity_pointer
|
|
|
|
|
|
|
|
.run_if(in_state(GameState::Play))
|
|
|
|
|
|
|
|
.run_if(in_state(DisplayState::Display3d))
|
|
|
|
|
|
|
|
// Run if in debug state on mouse events
|
|
|
|
|
|
|
|
// Or just run when the left mouse button is clicked
|
|
|
|
|
|
|
|
.run_if(
|
|
|
|
|
|
|
|
in_state(debug::DebugState::Enabled)
|
|
|
|
|
|
|
|
.and_then(on_event::<MouseMotion>())
|
|
|
|
|
|
|
|
.or_else(just_pressed(MouseButton::Left))
|
|
|
|
|
|
|
|
),
|
|
|
|
select
|
|
|
|
select
|
|
|
|
.run_if(in_state(GameState::Play))
|
|
|
|
.run_if(in_state(GameState::Play))
|
|
|
|
.run_if(in_state(DisplayState::Display3d))
|
|
|
|
.run_if(in_state(DisplayState::Display3d))
|
|
|
|
@ -653,27 +664,44 @@ fn update_pieces(
|
|
|
|
);
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn select(
|
|
|
|
|
|
|
|
// Query Selectable with BoardIndex
|
|
|
|
|
|
|
|
query: Query<(&BoardIndex, &Side), With<Selectable>>,
|
|
|
|
|
|
|
|
piece: Res<PiecePointer>,
|
|
|
|
|
|
|
|
mut selections: EventWriter<game::Selection>,
|
|
|
|
|
|
|
|
selected: Query<Entity, With<game::Selected>>,
|
|
|
|
|
|
|
|
state: Res<State<game::TurnState>>,
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
// info!("Board index selected: {:?}", board_index);
|
|
|
|
|
|
|
|
match *piece {
|
|
|
|
|
|
|
|
PiecePointer(Some(e)) => {
|
|
|
|
|
|
|
|
query.get(e).iter().for_each(|(board_index, side)| {
|
|
|
|
|
|
|
|
let side_check = !selected.is_empty() || state.get().0 == **side;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if side_check {
|
|
|
|
|
|
|
|
selections.send(game::Selection(**board_index));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
_ => ()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Default, Resource)]
|
|
|
|
|
|
|
|
struct PiecePointer(Option<Entity>);
|
|
|
|
|
|
|
|
|
|
|
|
/// Select tiles and pieces in 3d
|
|
|
|
/// Select tiles and pieces in 3d
|
|
|
|
/// There is a bug where we are selecting multiple entities...
|
|
|
|
/// There is a bug where we are selecting multiple entities...
|
|
|
|
/// TODO: Selectable generalize picking pieces **and** hitboxes
|
|
|
|
/// TODO: Selectable generalize picking pieces **and** hitboxes
|
|
|
|
fn select(
|
|
|
|
fn entity_pointer(
|
|
|
|
mut events: EventReader<MouseButtonInput>,
|
|
|
|
|
|
|
|
query: Query<(Entity, &Handle<Mesh>, &GlobalTransform)>,
|
|
|
|
query: Query<(Entity, &Handle<Mesh>, &GlobalTransform)>,
|
|
|
|
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, &BoardIndex, &Side), (With<game::Selectable>, With<Display3d>)>,
|
|
|
|
selectable: Query<Entity, (With<game::Selectable>, With<Display3d>)>,
|
|
|
|
selected: Query<Entity, With<game::Selected>>,
|
|
|
|
|
|
|
|
children: Query<&Children>,
|
|
|
|
children: Query<&Children>,
|
|
|
|
mut selections: EventWriter<game::Selection>,
|
|
|
|
mut pointer: ResMut<PiecePointer>,
|
|
|
|
state: Res<State<game::TurnState>>,
|
|
|
|
|
|
|
|
) {
|
|
|
|
) {
|
|
|
|
// For every mouse click event
|
|
|
|
|
|
|
|
events
|
|
|
|
|
|
|
|
.read()
|
|
|
|
|
|
|
|
// Only read button presses
|
|
|
|
|
|
|
|
.filter(|ev| ev.state == ButtonState::Pressed && ev.button == MouseButton::Left)
|
|
|
|
|
|
|
|
.for_each(|_| {
|
|
|
|
|
|
|
|
// For each window (there should be only one)
|
|
|
|
// For each window (there should be only one)
|
|
|
|
windows.iter().for_each(|window| {
|
|
|
|
windows.iter().for_each(|window| {
|
|
|
|
// Get the cursor position
|
|
|
|
// Get the cursor position
|
|
|
|
@ -683,7 +711,7 @@ fn select(
|
|
|
|
// Get a ray from the camera through the cursor into the world
|
|
|
|
// 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
|
|
|
|
// Iterate over every entity with a 3d scene
|
|
|
|
query
|
|
|
|
let selected = query
|
|
|
|
.iter()
|
|
|
|
.iter()
|
|
|
|
// Transform the scene handle into mesh data
|
|
|
|
// Transform the scene handle into mesh data
|
|
|
|
.filter_map(|(entity, handle, gt)| {
|
|
|
|
.filter_map(|(entity, handle, gt)| {
|
|
|
|
@ -698,12 +726,7 @@ fn select(
|
|
|
|
// Find this entity in the set of selectable entities
|
|
|
|
// Find this entity in the set of selectable entities
|
|
|
|
selectable
|
|
|
|
selectable
|
|
|
|
.iter()
|
|
|
|
.iter()
|
|
|
|
.find_map(|(e, &board_index, &side)| {
|
|
|
|
.find_map(|e| {
|
|
|
|
// Check the side of the selection if no piece is selected
|
|
|
|
|
|
|
|
// Otherwise this is fine, select away
|
|
|
|
|
|
|
|
let side_check =
|
|
|
|
|
|
|
|
!selected.is_empty() || state.get().0 == side;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let hit_check = {
|
|
|
|
let hit_check = {
|
|
|
|
// This entity was hit (tile hitboxes)
|
|
|
|
// This entity was hit (tile hitboxes)
|
|
|
|
let primary = entity == e;
|
|
|
|
let primary = entity == e;
|
|
|
|
@ -717,29 +740,20 @@ fn select(
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Return the board index of this piece
|
|
|
|
// Return the board index of this piece
|
|
|
|
(side_check && hit_check).then_some(board_index)
|
|
|
|
hit_check.then_some((e, hit.clone()))
|
|
|
|
})
|
|
|
|
|
|
|
|
.map(|board_index| {
|
|
|
|
|
|
|
|
// Include the hit from the camera
|
|
|
|
|
|
|
|
(hit, board_index)
|
|
|
|
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
// Compare the distance of all hits, choosing the closest one
|
|
|
|
// Compare the distance of all hits, choosing the closest one
|
|
|
|
.min_by(|(hit_a, _), (hit_b, _)| {
|
|
|
|
.min_by(|(_, hit_a), (_, hit_b)| {
|
|
|
|
hit_a.distance.partial_cmp(&hit_b.distance).unwrap()
|
|
|
|
hit_a.distance.partial_cmp(&hit_b.distance).unwrap()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
// Iterate over the 0 or 1 outcomes of the above
|
|
|
|
.map(|(e, _)| e);
|
|
|
|
.iter()
|
|
|
|
|
|
|
|
// Send an event that this board index was selected
|
|
|
|
*pointer = PiecePointer(selected)
|
|
|
|
.for_each(|(_, board_index)| {
|
|
|
|
|
|
|
|
info!("Board index selected: {:?}", board_index);
|
|
|
|
|
|
|
|
selections.send(game::Selection(*board_index));
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn selected_gizmo(
|
|
|
|
fn selected_gizmo(
|
|
|
|
|