Moving in the right direction for movement checking

main
Elijah Voigt 2 weeks ago
parent c21636629e
commit c4394f9728

@ -115,13 +115,43 @@ struct Line(u8);
#[derive(Component, Debug)] #[derive(Component, Debug)]
struct Block; struct Block;
#[derive(Component, Debug)] #[derive(Component, Event, Debug)]
#[require(GridPosition)] #[require(GridPosition)]
struct RelativePosition { struct RelativePosition {
x: i8, x: i8,
y: i8, y: i8,
} }
impl RelativePosition {
fn up() -> Self {
RelativePosition {
x: 0,
y: 1,
}
}
fn down() -> Self {
RelativePosition {
x: 0,
y: -1,
}
}
fn left() -> Self {
RelativePosition {
x: -1,
y: 0,
}
}
fn right() -> Self {
RelativePosition {
x: 1,
y: 0,
}
}
}
impl From<(i8, i8)> for RelativePosition { impl From<(i8, i8)> for RelativePosition {
fn from((x, y): (i8, i8)) -> RelativePosition { fn from((x, y): (i8, i8)) -> RelativePosition {
RelativePosition { x, y } RelativePosition { x, y }
@ -176,15 +206,29 @@ impl GridPosition {
self.x == other.x && self.y.saturating_sub(1) == other.y self.x == other.x && self.y.saturating_sub(1) == other.y
} }
fn add_offset(&self, RelativePosition { x: x1, y: y1 }: &RelativePosition) -> Self { fn add_offset(&self, RelativePosition { x: x1, y: y1 }: &RelativePosition) -> Result<Self, GameError> {
debug!("{} + {}, {} + {}", self.x, *x1 as i32, self.y, *y1 as i32); let x = self.x.checked_add_signed(*x1 as i32).ok_or(GameError::OutOfBoundsLeft)?;
GridPosition { let y = self.y.checked_add_signed(*y1 as i32).ok_or(GameError::OutOfBoundsDown)?;
x: self.x.checked_add_signed(*x1 as i32).unwrap(), if x >= X_MAX { // TODO: y > Y_MAX?
y: self.y.checked_add_signed(*y1 as i32).unwrap(), Err(GameError::OutOfBoundsRight)
} else {
Ok(GridPosition { x, y })
} }
} }
} }
#[derive(Error, Debug)]
enum GameError {
#[error("Coordinates are out of bounds: Left")]
OutOfBoundsLeft,
#[error("Coordinates are out of bounds: Right")]
OutOfBoundsRight,
#[error("Coordinates are out of bounds: Down")]
OutOfBoundsDown,
#[error("Coordiante collision")]
Collision,
}
impl Default for GridPosition { impl Default for GridPosition {
fn default() -> Self { fn default() -> Self {
GridPosition { x: 5, y: Y_MAX } GridPosition { x: 5, y: Y_MAX }
@ -229,7 +273,7 @@ impl std::ops::AddAssign<&GridPosition> for GridPosition {
} }
} }
#[derive(Component, Default, Debug)] #[derive(Component, Default, Event, Clone, Debug)]
enum Orientation { enum Orientation {
#[default] #[default]
Up, Up,
@ -503,9 +547,10 @@ fn update_position(mut query: Query<(&GridPosition, &mut Transform), Changed<Gri
fn kb_input( fn kb_input(
mut events: EventReader<KeyboardInput>, mut events: EventReader<KeyboardInput>,
mut query: Query<(&mut GridPosition, &mut Orientation, &mut Shape)>, mut query: Query<(Entity, &Orientation, &mut Shape)>,
curr: Res<State<Falling>>, curr: Res<State<Falling>>,
mut next: ResMut<NextState<Falling>>, mut next: ResMut<NextState<Falling>>,
mut commands: Commands,
) { ) {
events.read().for_each( events.read().for_each(
|KeyboardInput { |KeyboardInput {
@ -514,14 +559,22 @@ fn kb_input(
if let ButtonState::Pressed = state { if let ButtonState::Pressed = state {
// TODO: Restict movement based on size/orientation of piece // TODO: Restict movement based on size/orientation of piece
// Check if children would be outside play area... // Check if children would be outside play area...
query.iter_mut().for_each(|(mut gp, mut o, mut s)| { query.iter_mut().for_each(|(e, o, mut s)| {
match key_code { match key_code {
// Up arrow should rotate if in falling mode // Up arrow should rotate if in falling mode
// Only move up if in falling::off mode // Only move up if in falling::off mode
KeyCode::ArrowUp => *o = o.prev(), KeyCode::ArrowUp => {
KeyCode::ArrowDown => *gp = gp.move_down(), commands.entity(e).trigger(o.prev());
KeyCode::ArrowLeft => *gp = gp.move_left(), }
KeyCode::ArrowRight => *gp = gp.move_right(), KeyCode::ArrowDown => {
commands.entity(e).trigger(RelativePosition::down());
},
KeyCode::ArrowLeft => {
commands.entity(e).trigger(RelativePosition::left());
},
KeyCode::ArrowRight => {
commands.entity(e).trigger(RelativePosition::right());
},
KeyCode::Space => next.set(match curr.get() { KeyCode::Space => next.set(match curr.get() {
Falling::On => Falling::Off, Falling::On => Falling::Off,
Falling::Off => Falling::On, Falling::Off => Falling::On,
@ -552,14 +605,9 @@ fn draw_grid(mut gizmos: Gizmos) {
.outer_edges(); .outer_edges();
} }
fn falling(mut shape: Query<&mut GridPosition, With<Shape>>) { fn falling(mut shape: Query<Entity, With<Shape>>, mut commands: Commands) {
shape.iter_mut().for_each(|mut gp| { shape.iter_mut().for_each(|e| {
let next = gp.move_down(); commands.entity(e).trigger(RelativePosition::down());
if next != *gp {
*gp = next;
} else {
// TODO: What to do here??
}
}); });
} }
@ -576,7 +624,7 @@ fn shape_block_movement(
) { ) {
shape.iter().for_each(|shape_gp| { shape.iter().for_each(|shape_gp| {
blocks.iter_mut().for_each(|(mut block_gp, block_rp)| { blocks.iter_mut().for_each(|(mut block_gp, block_rp)| {
*block_gp = shape_gp.add_offset(block_rp); *block_gp = shape_gp.add_offset(block_rp).expect("Cannot move there...");
}); });
}); });
} }
@ -646,7 +694,7 @@ fn check_collision(
fn add_piece(mut commands: Commands) { fn add_piece(mut commands: Commands) {
// TODO: Choose a different piece // TODO: Choose a different piece
commands.spawn((Orientation::default(), GridPosition::default(), Shape::T)); commands.spawn((Orientation::default(), GridPosition::default(), Shape::T)).observe(movement).observe(rotation);
} }
/// When a line reaches 10 blocks, clear it /// When a line reaches 10 blocks, clear it
@ -659,7 +707,57 @@ fn clear_line(
commands.entity(e).despawn_related::<LineBlocks>(); commands.entity(e).despawn_related::<LineBlocks>();
// TODO: re-parent all blocks above this to the next line down // TODO: re-parent all blocks above this to the next line down
// TODO: Parent blocks to lines for movement // TODO: Parent blocks to lines for movement
} }
}); });
} }
fn movement(
trigger: Trigger<RelativePosition>,
mut shapes: Query<&mut GridPosition, With<Shape>>,
mut active: Query<&mut GridPosition, (With<RelativePosition>, Without<Shape>)>,
inactive: Query<&GridPosition, (Without<RelativePosition>, Without<Shape>)>,
blocks: Query<&ShapeBlocks>,
mut commands: Commands,
) {
// Find any errors
for block in blocks.iter_descendants(trigger.target()) {
// Get the child's grid position
let gp = active.get(block).unwrap();
match gp.add_offset(trigger.event()) {
// If this would go out of bounds to the left or right, prevent this move
Err(GameError::OutOfBoundsLeft) | Err(GameError::OutOfBoundsRight) => {
return
}
// If this would go out of bounds down, or cause a collision, remove the active
// component from the piece
Err(GameError::OutOfBoundsDown) | Err(GameError::Collision) => {
// remove active component
commands.entity(trigger.target()).remove::<Shape>();
return
}
Ok(new_gp) => {
// If any children collide with the new position, remove the active component
if inactive.iter().any(|other_gp| new_gp == *other_gp) {
commands.entity(trigger.target()).remove::<Shape>();
return
}
}
}
}
// If the above checks went ok, we can move
let mut gp = shapes.get_mut(trigger.target()).unwrap();
*gp = gp.add_offset(trigger.event()).unwrap();
}
fn rotation(
trigger: Trigger<Orientation>,
mut q: Query<(&mut Orientation, &mut GridPosition)>,
) {
let (mut o, mut _gp) = q.get_mut(trigger.target()).unwrap();
// If children would go out of bounds to the left
// If children would not go out of bounds to the right
// If children would not go out of bounds to the down
*o = trigger.event().clone();
}

Loading…
Cancel
Save