diff --git a/tetris/src/blocks.rs b/tetris/src/blocks.rs index 95a773b..b2d0889 100644 --- a/tetris/src/blocks.rs +++ b/tetris/src/blocks.rs @@ -1,17 +1,14 @@ +#![allow(clippy::single_match)] #![allow(clippy::type_complexity)] use super::*; // TODO: // - When shape asset is updated, shape layout update in real time -// - Debug: gizmo outline entities -// - conditional enable/disable -// - entities without mesh should draw empty cross // - Debug: gizmo draw relationship lines // - conditional enable/disable // - Debug: show FPS // - conditional enable/disable -// - Line entities // - Debug: Nametags // - If it has a Name component, display that at the same Translation // - Disable shape when placed @@ -31,6 +28,7 @@ impl Plugin for BlocksPlugin { app.init_asset::() .init_asset_loader::() .add_message::() + .add_message::() .add_systems(OnEnter(Loading(true)), load_assets.run_if(run_once)) .add_systems( OnEnter(GameState::Setup), @@ -49,6 +47,7 @@ impl Plugin for BlocksPlugin { propogate_relative_position.run_if(any_component_changed::), handle_kb_input.run_if(on_message::), handle_movement.run_if(on_message::), + handle_shape_event.run_if(on_message::), ), ) .add_observer(add_shape) @@ -108,11 +107,11 @@ struct GridPosition { #[derive(Debug, Error)] enum GridPositionError { #[error("X > X_MAX")] - XOver, + HitRight, #[error("X < 0")] - XUnder, + HitLeft, #[error("Y < 0")] - YUnder, + HitFloor, #[error("Y < 0 && X < 0")] BothUnder, } @@ -130,17 +129,17 @@ impl GridPosition { // Both underflow (None, None) => Err(GridPositionError::BothUnder), // Just y underflows - (None, Some(_)) => Err(GridPositionError::XUnder), + (None, Some(_)) => Err(GridPositionError::HitLeft), // y underflow or x overflow (Some(x), None) => match x { - 0..X_MAX => Err(GridPositionError::YUnder), - _ => Err(GridPositionError::XOver), - } + 0..X_MAX => Err(GridPositionError::HitFloor), + _ => Err(GridPositionError::HitRight), + }, // both good, may x overflow (Some(x), Some(y)) => match x { - 0..X_MAX => Ok(GridPosition { x, y }), - _ => Err(GridPositionError::XOver), - } + 0..X_MAX => Ok(GridPosition { x, y }), + _ => Err(GridPositionError::HitRight), + }, } } } @@ -539,6 +538,12 @@ enum Movement { Right, } +/// Things that can happen to a shape +#[derive(Debug, Message, PartialEq)] +enum ShapeEvent { + Deactivate, +} + /// Handle KeyBoard input /// Nothing is handled directly in this method, /// All key presses result in either a message, event, or state change @@ -592,40 +597,54 @@ impl Orientation { fn handle_movement( mut moves: MessageReader, mut shapes: Query<(&ShapeLayout, &mut GridPosition, &mut Orientation)>, + mut writer: MessageWriter, ) { - moves.read().for_each(|m| { - shapes.iter_mut().for_each(|(shape_layout, mut gp, mut o)| { + 'outer: for m in moves.read() { + for (shape_layout, mut gp, mut o) in shapes.iter_mut() { // First determine if proposed positions are valid // Determine next orientation - let proposed_orientation = if *m == Movement::Rotate { - o.rotated() - } else { - *o + let proposed_orientation = match *m == Movement::Rotate { + true => o.rotated(), + false => *o, }; // And next position - let proposed_position = match m { - Movement::Left => gp.add((-1, 0).into()), - Movement::Right => gp.add((1, 0).into()), - Movement::Down => gp.add((0, -1).into()), - Movement::Rotate => Ok(gp.clone()), + let offset: RelativePosition = match m { + Movement::Left => (-1, 0).into(), + Movement::Right => (1, 0).into(), + Movement::Down => (0, -1).into(), + Movement::Rotate => (0, 0).into(), }; - if let Ok(pp) = proposed_position { - // Check that new positions are all valid - if shape_layout - .positions(proposed_orientation) - .iter() - .all(|rp| pp.add(*rp).is_ok()) { - // then commit the movement - *gp = pp; - *o = proposed_orientation; - } else { - // invalid position! + // TODO: See if the proposed position would collide with another block + // If would collide downward, deactivate shape + + // Check that new positions are all valid for all blocks + for pos in shape_layout.positions(proposed_orientation).iter() { + match gp.add(*pos).unwrap().add(offset) { + Err(e) => { + match e { + GridPositionError::HitFloor => { + writer.write(ShapeEvent::Deactivate); + } + _ => (), // Other errors are just ignored + } + // Either way skip the rest of this iteration of the loop + continue 'outer; + } + Ok(_) => (), // Ignore OKs as no [bad] news is good news } - } else { - // Invalid move! } - }); + + // If those checks went well, commit the proposed changes + *gp = gp.add(offset).unwrap(); + *o = proposed_orientation; + } + } +} + +fn handle_shape_event(mut reader: MessageReader) { + reader.read().for_each(|msg| match msg { + ShapeEvent::Deactivate => warn!("TODO: Deactivate shape"), }); }