Detecting when to deactivate a piece

At least when there are no other blocks on the board...
main
Elijah Voigt 1 month ago
parent a668b946f2
commit cea796325e

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

Loading…
Cancel
Save