Saving place. Broken but don't want to go further...

main
Elijah C. Voigt 2 years ago
parent b86aea043e
commit 2fb524643d

@ -222,7 +222,17 @@ fn selected_position(
}
fn debug_piece(
query: Query<(Entity, Option<&Side>, Option<&Piece>, Option<&BoardIndex>, Option<&display3d::Animating>, Option<&Selected>), With<Piece>>,
query: Query<
(
Entity,
Option<&Side>,
Option<&Piece>,
Option<&BoardIndex>,
Option<&display3d::Animating>,
Option<&Selected>,
),
With<Piece>,
>,
pointer: Res<display3d::PiecePointer>,
mut root: Query<(&mut Text, &mut Visibility), With<DebugPiece>>,
// mut commands: Commands,
@ -239,11 +249,11 @@ fn debug_piece(
*vis = Visibility::Inherited;
});
}
},
}
_ => {
root.iter_mut().for_each(|(_, mut vis)| {
*vis = Visibility::Hidden;
});
}
}
}
}

@ -78,8 +78,9 @@ impl Plugin for Display3dPlugin {
.run_if(
in_state(debug::DebugState::Enabled)
.and_then(on_event::<MouseMotion>())
.or_else(just_pressed(MouseButton::Left))
).before(select),
.or_else(just_pressed(MouseButton::Left)),
)
.before(select),
select
.run_if(in_state(GameState::Play))
.run_if(in_state(DisplayState::Display3d))
@ -118,7 +119,7 @@ impl Plugin for Display3dPlugin {
(
animate_title_light_in.run_if(in_state(DissolvingAnimation::In)),
animate_title_light_out.run_if(in_state(DissolvingAnimation::Out)),
)
),
)
.add_systems(
OnEnter(GameState::Intro),
@ -133,11 +134,12 @@ impl Plugin for Display3dPlugin {
)
.add_systems(
Update,
setup_dissolve_materials.run_if(in_state(GameState::Intro))
setup_dissolve_materials
.run_if(in_state(GameState::Intro))
.run_if(
any_component_added::<Handle<StandardMaterial>>()
.or_else(any_component_changed::<Handle<StandardMaterial>>()),
),
any_component_added::<Handle<StandardMaterial>>()
.or_else(any_component_changed::<Handle<StandardMaterial>>()),
),
)
.add_systems(
OnEnter(GameState::Play),
@ -186,7 +188,7 @@ enum DissolvingAnimation {
#[default]
None,
In,
Out
Out,
}
#[derive(Debug, Resource, Clone)]
@ -487,7 +489,10 @@ fn set_board_model(
}
fn set_title_model(
mut titles: Query<(&mut Handle<Scene>, &mut Transform, &mut Visibility), (Added<TitleText>, With<Display3d>)>,
mut titles: Query<
(&mut Handle<Scene>, &mut Transform, &mut Visibility),
(Added<TitleText>, With<Display3d>),
>,
gltfs: Res<Assets<Gltf>>,
tweaks: Res<Assets<Tweaks>>,
tweaks_file: Res<tweak::GameTweaks>,
@ -495,29 +500,31 @@ fn set_title_model(
let tweak = tweaks
.get(tweaks_file.handle.clone())
.expect("Load tweakfile");
titles.iter_mut().for_each(|(mut handle, mut transform, mut visibility)| {
info!("Setting title model");
let assets_handle = tweak
.get_handle::<Gltf>("display3d_models_assets_file")
.unwrap();
let gltf = gltfs.get(assets_handle).expect("Load GLTF content");
*handle = gltf
.named_scenes
.get(
tweak
.get::<String>("display3d_models_scenes_title")
.unwrap()
.as_str(),
)
.expect("Game title model")
.clone();
titles
.iter_mut()
.for_each(|(mut handle, mut transform, mut visibility)| {
info!("Setting title model");
let assets_handle = tweak
.get_handle::<Gltf>("display3d_models_assets_file")
.unwrap();
let gltf = gltfs.get(assets_handle).expect("Load GLTF content");
*handle = gltf
.named_scenes
.get(
tweak
.get::<String>("display3d_models_scenes_title")
.unwrap()
.as_str(),
)
.expect("Game title model")
.clone();
transform.translation -= Vec3::Y * 0.5;
transform.rotate_local_z(std::f32::consts::PI);
transform.rotate_local_y(std::f32::consts::PI / 2.0);
transform.translation -= Vec3::Y * 0.5;
transform.rotate_local_z(std::f32::consts::PI);
transform.rotate_local_y(std::f32::consts::PI / 2.0);
*visibility = Visibility::Hidden;
});
*visibility = Visibility::Hidden;
});
}
/// Given a board index returns the Vec3 location in space
@ -682,8 +689,8 @@ fn select(
selections.send(game::Selection(**board_index));
}
});
},
_ => ()
}
_ => (),
}
}
@ -724,24 +731,21 @@ fn entity_pointer(
})
.filter_map(|(entity, hit)| {
// Find this entity in the set of selectable entities
selectable
.iter()
.find_map(|e| {
let hit_check = {
// 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
};
// Return the board index of this piece
hit_check.then_some((e, hit.clone()))
})
selectable.iter().find_map(|e| {
let hit_check = {
// 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
};
// Return the board index of this piece
hit_check.then_some((e, hit.clone()))
})
})
// Compare the distance of all hits, choosing the closest one
.min_by(|(_, hit_a), (_, hit_b)| {
@ -840,11 +844,12 @@ fn pick_up(
children.iter_descendants(entity).for_each(|child| {
info!(" Child: {:?}", child);
if let Ok((name, mut player)) = players.get_mut(child) {
let pickup_animation = format!(
"display3d_models_animations_pick_up_{}",
name.as_str(),
let pickup_animation =
format!("display3d_models_animations_pick_up_{}", name.as_str(),);
info!(
"Picking up {:?} ({:?}) {:?} {:?}",
name, entity, piece, pickup_animation
);
info!("Picking up {:?} ({:?}) {:?} {:?}", name, entity, piece, pickup_animation);
let pickup_handle = gltf
.named_animations
.get(
@ -854,10 +859,7 @@ fn pick_up(
.as_str(),
)
.expect("Pickup Animation");
let idle_animation = format!(
"display3d_models_animations_idle_{}",
name.as_str()
);
let idle_animation = format!("display3d_models_animations_idle_{}", name.as_str());
let idle_handle = gltf
.named_animations
.get(
@ -890,10 +892,7 @@ fn pick_up(
fn put_down(
mut events: RemovedComponents<game::Selected>,
mut query: Query<
Entity,
(With<game::Piece>, With<game::Selectable>, With<Display3d>),
>,
mut query: Query<Entity, (With<game::Piece>, With<game::Selectable>, With<Display3d>)>,
gltfs: Res<Assets<Gltf>>,
children: Query<&Children>,
mut players: Query<(&Name, &mut AnimationPlayer)>,
@ -915,7 +914,8 @@ fn put_down(
children.iter_descendants(entity).for_each(|child| {
if let Ok((name, mut player)) = players.get_mut(child) {
info!("Putting down {:?}", entity);
let putdown_animation = format!("display3d_models_animations_put_down_{}", name.as_str());
let putdown_animation =
format!("display3d_models_animations_put_down_{}", name.as_str());
let putdown_handle = gltf
.named_animations
.get(
@ -935,7 +935,10 @@ fn put_down(
)
.set_repeat(RepeatAnimation::Never);
} else {
info!("Clip {:?}({:?}) not compatible with {:?}", putdown_animation, putdown_clip, name);
info!(
"Clip {:?}({:?}) not compatible with {:?}",
putdown_animation, putdown_clip, name
);
}
} else {
info!("Clip not found");
@ -1481,4 +1484,4 @@ fn animate_title_light_out(
}
})
});
}
}

@ -118,6 +118,13 @@ impl Piece {
.iter(),
}
}
fn moves_at(&self, from: &BoardIndex) -> Vec<BoardIndex> {
self.moves().map(|(x, y)| {
*from + (*x, *y)
})
.collect()
}
}
#[derive(Debug, Component, Clone, PartialEq)]
@ -280,12 +287,29 @@ impl std::ops::Add<(isize, isize)> for BoardIndex {
fn add(self, (a, b): (isize, isize)) -> Self {
BoardIndex {
x: self.x.saturating_add_signed(a),
y: self.y.saturating_add_signed(b),
x: self.x.saturating_add_signed(a).max(7),
y: self.y.saturating_add_signed(b).max(3),
}
}
}
impl std::ops::Add<(usize, usize)> for BoardIndex {
type Output = BoardIndex;
fn add(self, (a, b): (usize, usize)) -> Self {
BoardIndex {
x: self.x.saturating_add(a).max(7),
y: self.y.saturating_add(b).max(3),
}
}
}
impl From<(usize, usize)> for BoardIndex {
fn from((x, y): (usize, usize)) -> BoardIndex {
BoardIndex { x, y }
}
}
#[derive(Debug)]
pub(crate) enum MoveType {
Valid,
@ -320,24 +344,33 @@ impl Board {
fn from_ascii(art: &str) -> Board {
use Piece::*;
let mut inner: Vec<Vec<Option<Piece>>> = vec![Vec::with_capacity(8), Vec::with_capacity(8), Vec::with_capacity(8), Vec::with_capacity(8)];
let mut inner: Vec<Vec<Option<Piece>>> = vec![
Vec::with_capacity(8),
Vec::with_capacity(8),
Vec::with_capacity(8),
Vec::with_capacity(8),
];
let mut index = BoardIndex { x: 0, y: 3 };
art.chars().for_each(|c| {
match c {
'q' => {
'q' | 'Q' => {
inner[index.y].push(Some(Queen));
}
'd' => {
'd' | 'D' => {
inner[index.y].push(Some(Drone));
},
'p' => {
}
'p' | 'P' => {
inner[index.y].push(Some(Pawn));
},
'.' => {
}
'.' | '#' => {
inner[index.y].push(None);
},
}
'\n' => {
assert_eq!(inner[index.y].len(), 8, "Each row must be 8 characters long!");
assert_eq!(
inner[index.y].len(),
8,
"Each row must be 8 characters long!"
);
index.y -= 1;
}
_ => {
@ -356,7 +389,8 @@ impl Board {
r#".....dqq
dpp..pdq
qdp..ppd
qqd....."#)
qqd....."#,
)
}
/// Show all pieces on one side of the board
@ -501,9 +535,10 @@ impl Board {
) -> Option<MoveType> {
// Iterate over the piece's moves
piece
.moves()
.moves_at(&from)
.iter()
// Find if the given `to` move is one of those
.find(|(x, y)| to == from + (*x, *y))
.find(|BoardIndex { x, y }| to == from + (*x, *y))
// Determine if this is valid/legal in this situation
.and_then(|_| {
let dest_at = self.at(to);
@ -584,17 +619,18 @@ impl Board {
/// Returns the possible moves the piece at this tile can make.
pub(crate) fn valid_moves(&self, current_board_index: BoardIndex) -> HashSet<BoardIndex> {
tiles()
.filter_map(|(board_index, _)| {
if let Some(piece) = self.at(current_board_index) {
piece.moves_at(&current_board_index).iter().filter_map(|move_index| {
// Get the move type (or none if totally invalid)
self.at(current_board_index).and_then(|piece| {
match self.move_type(*piece, current_board_index, board_index) {
None | Some(MoveType::Invalid) => None,
_ => Some(board_index),
}
})
match self.move_type(*piece, current_board_index, *move_index) {
None | Some(MoveType::Invalid) => None,
_ => Some(*move_index),
}
})
.collect()
} else {
HashSet::new()
}
}
pub(crate) fn current_epoch(&self) -> usize {
@ -606,14 +642,161 @@ mod test {
use super::*;
#[test]
fn test_01() {
let mut board = Board::new();
print!("{}", board);
println!("{:?}", board.at(BoardIndex { x: 0, y: 0 }));
println!("{:?}", board.at(BoardIndex { x: 1, y: 0 }));
println!("{:?}", board.at(BoardIndex { x: 2, y: 0 }));
println!("{:?}", board.at(BoardIndex { x: 3, y: 0 }));
todo!()
fn pawn_simple_moves() {
let board = Board::from_ascii(
r#"........
.#.#....
..p.....
.#.#...."#,
);
let given = board.valid_moves((2, 1).into());
let expected: HashSet<BoardIndex> =
HashSet::from([(1, 0).into(), (3, 0).into(), (1, 2).into(), (3, 2).into()]);
assert_eq!(expected, given, "Basic pawn moves");
}
#[test]
fn drone_simple_moves() {
let board = Board::from_ascii(
r#"..#.....
..#.....
##d##...
..#....."#,
);
let given = board.valid_moves((2, 1).into());
let expected: HashSet<BoardIndex> = HashSet::from([
(2, 0).into(),
(2, 2).into(),
(2, 3).into(),
(0, 1).into(),
(1, 1).into(),
(3, 1).into(),
(4, 1).into(),
]);
assert_eq!(expected, given, "Basic drone moves");
}
#[test]
fn queen_simple_moves() {
let board = Board::from_ascii(
r#"...###..
####q###
...###..
..#.#.#."#,
);
let given = board.valid_moves((4, 2).into());
let expected: HashSet<BoardIndex> = HashSet::from([
(0, 2).into(),
(1, 0).into(),
(1, 2).into(),
(2, 0).into(),
(2, 2).into(),
(3, 1).into(),
(3, 2).into(),
(3, 3).into(),
(4, 0).into(),
(4, 1).into(),
(4, 3).into(),
(5, 1).into(),
(5, 2).into(),
(5, 3).into(),
(6, 0).into(),
(6, 2).into(),
(7, 0).into(),
(7, 2).into(),
]);
assert_eq!(expected, given, "Basic queen moves");
}
#[test]
fn empty_moves() {
let board = Board::from_ascii(
r#"........
.p....q.
........
...d...."#,
);
let given = board.valid_moves((2, 1).into());
let expected: HashSet<BoardIndex> = HashSet::from([]);
assert_eq!(expected, given, "Empty moves");
}
/// When a piece is blocked on all sides by friendly, cannot move
#[test]
fn blocking_friendly() {
let board = Board::from_ascii(
r#"p.......
..dp....
.pqp....
.ppp...."#,
);
// Check queen
{
let given = board.valid_moves((2, 1).into());
let expected: HashSet<BoardIndex> = HashSet::from([(1, 2).into()]);
assert_eq!(expected, given, "Mostly surrounded queen, some moves");
}
// Check pawn
{
let given = board.valid_moves((3, 1).into());
let expected: HashSet<BoardIndex> = HashSet::from([(4, 0).into(), (4, 2).into()]);
assert_eq!(expected, given, "Partially blocked pawn, some moves");
}
// Check drone
{
let given = board.valid_moves((2, 2).into());
let expected: HashSet<BoardIndex> =
HashSet::from([(0, 2).into(), (1, 2).into(), (2, 3).into()]);
assert_eq!(expected, given, "Partially blocked drone, some moves");
}
}
/// When an enemy is on one side, can move to capture just that piece
#[test]
fn case_03() {
let board = Board::from_ascii(
r#"........
........
ppp.....
pq..p..p"#,
);
{
let given = board.valid_moves((1, 0).into());
let expected: HashSet<BoardIndex> =
HashSet::from([(2, 0).into(), (3, 0).into(), (4, 0).into()]);
assert_eq!(
expected, given,
"Mostly blocked queen, moves include captures"
);
}
}
/// Can move up to but not over friendlies
#[test]
fn case_02() {
let board = Board::from_ascii(
r#"......qq
dpp#d#d.
qd##qppd
qq.###.."#,
);
{
let given = board.valid_moves((4, 1).into());
let expected: HashSet<BoardIndex> =
HashSet::from([
(3,0).into(), (4,0).into(), (5,0).into(), (2, 1).into(), (2, 3).into(), (3, 1).into(), (5, 1).into(), (3, 2).into(), (5, 2).into()
]);
assert_eq!(
expected, given,
"Mostly blocked queen, moves include captures"
);
}
}
}

@ -99,9 +99,7 @@ pub(crate) fn intersects3d(ray: &Ray3d, mesh: &Mesh, gt: &GlobalTransform) -> Op
&& triangle.normal().dot(c1) > 0.0
&& triangle.normal().dot(c2) > 0.0
};
hit.then_some(Hit3d {
distance: d,
})
hit.then_some(Hit3d { distance: d })
} else {
None
}

@ -22,8 +22,7 @@ impl Plugin for UiPlugin {
),
)
.add_systems(OnEnter(GameState::Intro), show_click_prompt)
.add_systems(OnExit(GameState::Title), hide_click_prompt)
;
.add_systems(OnExit(GameState::Title), hide_click_prompt);
}
}
@ -189,14 +188,14 @@ fn init_prompts(mut commands: Commands) {
});
}
fn show_click_prompt(
mut query: Query<(&mut Visibility, &Prompt)>,
) {
query.iter_mut().for_each(|(mut vis, _)| *vis = Visibility::Inherited);
fn show_click_prompt(mut query: Query<(&mut Visibility, &Prompt)>) {
query
.iter_mut()
.for_each(|(mut vis, _)| *vis = Visibility::Inherited);
}
fn hide_click_prompt(
mut query: Query<(&mut Visibility, &Prompt)>,
) {
query.iter_mut().for_each(|(mut vis, _)| *vis = Visibility::Hidden);
}
fn hide_click_prompt(mut query: Query<(&mut Visibility, &Prompt)>) {
query
.iter_mut()
.for_each(|(mut vis, _)| *vis = Visibility::Hidden);
}

Loading…
Cancel
Save