Rotation exists, but needs polish

main
Elijah Voigt 2 months ago
parent 467f81bee7
commit 92ee8c7598

@ -3,6 +3,9 @@ VERSION := `git rev-parse --short HEAD`
check: check:
cargo check -p tetris cargo check -p tetris
clippy:
cargo clippy -p tetris
run: run:
cargo run -p tetris cargo run -p tetris

@ -42,10 +42,11 @@ impl Plugin for BlocksPlugin {
Update, Update,
( (
updated_shape_asset.run_if(on_message::<AssetEvent<ShapeAsset>>), updated_shape_asset.run_if(on_message::<AssetEvent<ShapeAsset>>),
update_grid_position.run_if( update_grid_position_transform.run_if(
any_component_added::<GridPosition> any_component_added::<GridPosition>
.or(any_component_changed::<GridPosition>), .or(any_component_changed::<GridPosition>),
), ),
propogate_orientation.run_if(any_component_changed::<Orientation>),
propogate_grid_position.run_if(any_component_changed::<GridPosition>), propogate_grid_position.run_if(any_component_changed::<GridPosition>),
handle_kb_input.run_if(on_message::<KeyboardInput>), handle_kb_input.run_if(on_message::<KeyboardInput>),
handle_movement.run_if(on_message::<Movement>), handle_movement.run_if(on_message::<Movement>),
@ -84,6 +85,8 @@ impl ShapeAsset {
( (
GridPosition { x: 5, y: 5 }, // TEMP GridPosition { x: 5, y: 5 }, // TEMP
self.layout.clone(),
Orientation::Up,
related!(ShapeBlocks[ related!(ShapeBlocks[
(self.mesh.clone(), self.material.clone(), a), (self.mesh.clone(), self.material.clone(), a),
(self.mesh.clone(), self.material.clone(), b), (self.mesh.clone(), self.material.clone(), b),
@ -164,12 +167,13 @@ impl From<(isize, isize)> for RelativePosition {
} }
/// Layout for a given shape /// Layout for a given shape
#[derive(Debug, Deserialize)] #[derive(Debug, Component, Deserialize, PartialEq, Clone)]
pub(crate) struct ShapeLayout(pub Vec<Vec<u8>>); pub(crate) struct ShapeLayout(pub Vec<Vec<u8>>);
impl ShapeLayout { impl ShapeLayout {
pub(crate) fn positions(&self) -> [RelativePosition; 4] { pub(crate) fn positions(&self) -> [RelativePosition; 4] {
let mut c: Vec<RelativePosition> = Vec::with_capacity(4); let mut c: Vec<RelativePosition> = Vec::with_capacity(4);
let center: (isize, isize) = { let center: (isize, isize) = {
// This could be less lines of code but it would be confusing af // This could be less lines of code but it would be confusing af
let y = if self.0.len() % 2 == 1 { let y = if self.0.len() % 2 == 1 {
@ -200,6 +204,44 @@ impl ShapeLayout {
[c[0], c[1], c[2], c[3]] [c[0], c[1], c[2], c[3]]
} }
pub(crate) fn rotated(&self, o: Orientation) -> Self {
info!("Rotation: {:?} {:?}", o, self);
// Now we have the base layout, rotate it based on orientation
match o {
Orientation::Up => {
// The identity
self.clone()
}
Orientation::Right => {
// The main algorithm
let cols = self.0[0].len();
let rows = self.0.len();
let mut rotated = vec![vec![0;rows];cols];
// (i, j) -> (j,rows-1-i)
for i in 0..rows {
for j in 0..cols {
rotated[j][rows - 1 - i] = self.0[i][j];
}
}
ShapeLayout(rotated)
}
Orientation::Down => {
// Implemented as repeated turns right
self.rotated(Orientation::Right)
.rotated(Orientation::Right)
}
Orientation::Left => {
// Implemented as repeated turns right
self.rotated(Orientation::Right)
.rotated(Orientation::Right)
.rotated(Orientation::Right)
}
}
}
} }
#[derive(Default)] #[derive(Default)]
@ -342,7 +384,7 @@ fn add_relative_position(
} }
/// Populate Transform when GridPosition is added to an entity /// Populate Transform when GridPosition is added to an entity
fn update_grid_position( fn update_grid_position_transform(
mut query: Query< mut query: Query<
(&GridPosition, &mut Transform), (&GridPosition, &mut Transform),
Or<(Added<GridPosition>, Changed<GridPosition>)>, Or<(Added<GridPosition>, Changed<GridPosition>)>,
@ -354,6 +396,7 @@ fn update_grid_position(
}); });
} }
/// When grid position is updated on a shape, apply that to blocks
fn propogate_grid_position( fn propogate_grid_position(
parent: Query<(&GridPosition, &ShapeBlocks), Changed<GridPosition>>, parent: Query<(&GridPosition, &ShapeBlocks), Changed<GridPosition>>,
mut children: Query<(&mut GridPosition, &RelativePosition), Without<ShapeBlocks>>, mut children: Query<(&mut GridPosition, &RelativePosition), Without<ShapeBlocks>>,
@ -366,6 +409,21 @@ fn propogate_grid_position(
}); });
} }
/// When a shape's orientation changes, the blocks need to move
fn propogate_orientation(
parent: Query<(&GridPosition, &Orientation, &ShapeLayout, &ShapeBlocks), Changed<Orientation>>,
mut children: Query<&mut GridPosition, Without<ShapeBlocks>>,
) {
parent.iter().for_each(|(parent_gp, parent_o, sl, sbs)| {
let new_layout = sl.rotated(*parent_o).positions();
sbs.iter().zip(new_layout).for_each(|(e, rp)| {
let mut gp = children.get_mut(e).unwrap();
*gp = parent_gp.clone() + rp;
});
});
}
/// Movement message used to propose/plan a move /// Movement message used to propose/plan a move
#[derive(Debug, Message)] #[derive(Debug, Message)]
enum Movement { enum Movement {
@ -405,31 +463,55 @@ fn handle_kb_input(mut input: MessageReader<KeyboardInput>, mut moves: MessageWr
); );
} }
#[derive(Component, Default, Debug, Clone, Copy)]
pub(crate) enum Orientation {
#[default]
Up,
Right,
Down,
Left,
}
impl Orientation {
fn rotated(&self) -> Orientation {
match self {
Orientation::Up => Orientation::Right,
Orientation::Right => Orientation::Down,
Orientation::Down => Orientation::Left,
Orientation::Left => Orientation::Up,
}
}
}
fn handle_movement( fn handle_movement(
mut moves: MessageReader<Movement>, mut moves: MessageReader<Movement>,
mut query: Query<&mut GridPosition, With<ShapeBlocks>>, mut grid_positions: Query<&mut GridPosition, With<ShapeBlocks>>,
mut orientations: Query<&mut Orientation, With<ShapeBlocks>>,
) { ) {
moves.read().for_each(|m| match m { moves.read().for_each(|m| match m {
Movement::Left => { Movement::Left => {
query.iter_mut().for_each(|mut gp| { grid_positions.iter_mut().for_each(|mut gp| {
info!("moving shape left"); info!("moving shape left");
*gp -= RelativePosition::new(1, 0); *gp -= RelativePosition::new(1, 0);
}); });
} }
Movement::Right => { Movement::Right => {
query.iter_mut().for_each(|mut gp| { grid_positions.iter_mut().for_each(|mut gp| {
info!("moving shape right"); info!("moving shape right");
*gp += RelativePosition::new(1, 0); *gp += RelativePosition::new(1, 0);
}); });
} }
Movement::Down => { Movement::Down => {
query.iter_mut().for_each(|mut gp| { grid_positions.iter_mut().for_each(|mut gp| {
info!("moving shape down"); info!("moving shape down");
*gp -= RelativePosition::new(0, 1); *gp -= RelativePosition::new(0, 1);
}); });
} }
Movement::Rotate => { Movement::Rotate => {
todo!() orientations.iter_mut().for_each(|mut o| {
info!("rotating shape");
*o = o.rotated();
});
} }
}) })
} }

@ -1,6 +1,8 @@
mod blocks; mod blocks;
mod debug; mod debug;
mod fighter; mod fighter;
#[cfg(test)]
mod test; mod test;
use engine::*; use engine::*;

@ -49,3 +49,45 @@ fn test_shape_layout_03() {
debug_assert_eq!(expected, actual); debug_assert_eq!(expected, actual);
} }
#[test]
fn test_rotation_01() {
let actual = ShapeLayout(vec![vec![1], vec![1], vec![1], vec![1]]).rotated(Orientation::Left);
let expected = ShapeLayout(vec![vec![1, 1, 1, 1]]);
debug_assert_eq!(expected, actual);
}
#[test]
fn test_rotation_02() {
let base = ShapeLayout(vec![vec![0, 1, 0], vec![1, 1, 1]]);
let expected_up = base.clone();
let actual_up = base.rotated(Orientation::Up);
let expected_down = ShapeLayout(vec![vec![1, 1, 1], vec![0, 1, 0]]);
let actual_down = base.rotated(Orientation::Down);
let expected_right = ShapeLayout(vec![vec![1, 0], vec![1, 1], vec![1, 0]]);
let actual_right = base.rotated(Orientation::Right);
let expected_left = ShapeLayout(vec![vec![0, 1], vec![1, 1], vec![0, 1]]);
let actual_left = base.rotated(Orientation::Left);
debug_assert_eq!(expected_up, actual_up);
debug_assert_eq!(expected_down, actual_down);
debug_assert_eq!(expected_right, actual_right);
debug_assert_eq!(expected_left, actual_left);
}
#[test]
fn test_rotation_03() {
let base = ShapeLayout(vec![vec![0, 1, 0], vec![1, 1, 1]]);
let actual_right = base.rotated(Orientation::Right);
let expected_right = ShapeLayout(vec![vec![1, 0], vec![1, 1], vec![1, 0]]);
debug_assert_eq!(expected_right, actual_right);
}

Loading…
Cancel
Save