Tighten up tetrino grid movement

main
Elijah Voigt 2 months ago
parent b51884ac69
commit 2cab218e5c

@ -25,15 +25,16 @@ fn main() {
falling falling
.run_if(in_state(Falling::On)) .run_if(in_state(Falling::On))
.run_if(clock_cycle(1.0)), .run_if(clock_cycle(1.0)),
set_piece set_piece.run_if(
.run_if(any_component_added::<Shape> any_component_added::<Shape>
.or(any_component_changed::<Shape>) .or(any_component_changed::<Shape>)
.or(any_component_added::<Orientation>) .or(any_component_added::<Orientation>)
.or(any_component_changed::<Orientation>) .or(any_component_changed::<Orientation>),
), ),
set_relative_piece_positions.run_if( shape_block_movement.run_if(
any_component_added::<RelativePosition> any_component_added::<RelativePosition>
.or(any_component_changed::<RelativePosition>), .or(any_component_changed::<RelativePosition>)
.or(any_component_changed::<GridPosition>),
), ),
sync_singleton_to_ui::<Shape>.run_if(any_component_changed::<Shape>), sync_singleton_to_ui::<Shape>.run_if(any_component_changed::<Shape>),
sync_singleton_to_ui::<Orientation>.run_if(any_component_changed::<Orientation>), sync_singleton_to_ui::<Orientation>.run_if(any_component_changed::<Orientation>),
@ -153,7 +154,7 @@ impl GridPosition {
} }
fn add_offset(&self, RelativePosition { x: x1, y: y1 }: &RelativePosition) -> Self { fn add_offset(&self, RelativePosition { x: x1, y: y1 }: &RelativePosition) -> Self {
info!("{} + {}, {} + {}", self.x, *x1 as i32, self.y, *y1 as i32); debug!("{} + {}, {} + {}", self.x, *x1 as i32, self.y, *y1 as i32);
GridPosition { GridPosition {
x: self.x.checked_add_signed(*x1 as i32).unwrap(), x: self.x.checked_add_signed(*x1 as i32).unwrap(),
y: self.y.checked_add_signed(*y1 as i32).unwrap(), y: self.y.checked_add_signed(*y1 as i32).unwrap(),
@ -237,9 +238,9 @@ impl Orientation {
impl Display for Orientation { impl Display for Orientation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
Orientation::Up => write!(f, "up"), Orientation::Up => write!(f, "up"),
Orientation::Down => write!(f, "down"), Orientation::Down => write!(f, "down"),
Orientation::Left => write!(f, "<-"), Orientation::Left => write!(f, "<-"),
Orientation::Right => write!(f, "->"), Orientation::Right => write!(f, "->"),
} }
} }
@ -272,188 +273,196 @@ fn init_pieces(
}); });
} }
fn init_debug_ui( fn init_debug_ui(mut commands: Commands) {
mut commands: Commands, commands
) { .spawn((
commands.spawn((Node { Node {
top: Val::Px(0.0), top: Val::Px(0.0),
left: Val::Px(0.0), left: Val::Px(0.0),
..default() ..default()
}, DebuggingState::On)).with_children(|parent| { },
parent.spawn(( DebuggingState::On,
Node::default(), ))
children![ .with_children(|parent| {
(Text::new("SHAPE"), SyncSingleton::<Shape>::default()), parent.spawn((
(Text::new("ORIENTATION"), SyncSingleton::<Orientation>::default()), Node::default(),
children![
(Text::new("SHAPE"), SyncSingleton::<Shape>::default()),
(
Text::new("ORIENTATION"),
SyncSingleton::<Orientation>::default()
),
],
));
});
}
#[rustfmt::skip]
fn block_positions(s: &Shape, o: &Orientation) -> [RelativePosition;4] {
match s {
Shape::O => [
(0,1).into(),(1,1).into(),
(0,0).into(),(1,0).into()
],
Shape::T => match o {
Orientation::Up => [
(0,1).into(),
(-1,0).into(),(0,0).into(),(1,0).into(),
],
Orientation::Down => [
(-1,0).into(),(0,0).into(),(1,0).into(),
(0,-1).into(),
],
Orientation::Right => [
(0,1).into(),
(0,0).into(), (1,0).into(),
(0,-1).into(),
],
Orientation::Left => [
(0,1).into(),
(-1,0).into(),(0,0).into(),
(0,-1).into(),
] ]
)); },
}); Shape::L => match o {
Orientation::Up => [
(0,1).into(),
(0,0).into(),
(0,-1).into(),(1,-1).into(),
],
Orientation::Down => [
(-1,1).into(),(0,1).into(),
(0,0).into(),
(0,-1).into(),
],
Orientation::Right => [
(-1,0).into(),(0,0).into(),(1,0).into(),
(-1,-1).into(),
],
Orientation::Left => [
(1,1).into(),
(-1,0).into(),(0,0).into(),(1,0).into(),
],
},
Shape::J => match o {
Orientation::Up => [
(0,1).into(),
(0,0).into(),
(-1,-1).into(),(0,-1).into(),
],
Orientation::Down => [
(0,1).into(),(1,1).into(),
(0,0).into(),
(0,-1).into(),
],
Orientation::Left => [
(-1,0).into(),(0,0).into(),(1,0).into(),
(1,-1).into(),
],
Orientation::Right => [
(-1,1).into(),
(-1,0).into(),(0,0).into(),(1,0).into()
],
},
Shape::S => match o {
Orientation::Up => [
(0,0).into(),(1,0).into(),
(-1,-1).into(),(0,-1).into(),
],
Orientation::Down => [
(0,1).into(),(1,1).into(),
(-1,0).into(),(0,0).into(),
],
Orientation::Right => [
(-1,1).into(),
(-1,0).into(),(0,0).into(),
(0,-1).into(),
],
Orientation::Left => [
(0,1).into(),
(0,0).into(),(1,0).into(),
(1,-1).into(),
],
},
Shape::Z => match o {
Orientation::Up => [
(-1,0).into(),(0,0).into(),
(0,-1).into(),(1,-1).into(),
],
Orientation::Down => [
(-1,1).into(),(0,1).into(),
(0,0).into(),(1,0).into(),
],
Orientation::Left => [
(1,1).into(),
(0,0).into(),(1,0).into(),
(0,-1).into(),
],
Orientation::Right => [
(0,1).into(),
(-1,0).into(),(0,0).into(),
(-1,-1).into(),
],
},
// TODO: This does not match tetris!
Shape::I => match o {
Orientation::Up => [
(0,2).into(),
(0,1).into(),
(0,0).into(),
(0,-1).into(),
],
Orientation::Down => [
(-1,2).into(),
(-1,1).into(),
(-1,0).into(),
(-1,-1).into(),
],
Orientation::Left => [
(-2,0).into(),(-1,0).into(),(0,0).into(),(1,0).into(),
],
Orientation::Right => [
(-2,1).into(),(-1,1).into(),(0,1).into(),(1,1).into(),
]
}
}
} }
fn set_piece( fn set_piece(
query: Query<(Entity, &Shape, &Orientation), Or<(Added<Shape>, Changed<Shape>, Added<Orientation>, Changed<Orientation>)>>, query: Query<
(Entity, &Shape, &Orientation),
Or<(
Added<Shape>,
Changed<Shape>,
Added<Orientation>,
Changed<Orientation>,
)>,
>,
mut blocks: Query<&mut RelativePosition, With<BlockOf>>,
mut commands: Commands, mut commands: Commands,
visuals: Res<Visuals>, visuals: Res<Visuals>,
) { ) {
query.iter().for_each(|(e, s, o)| { query.iter().for_each(|(e, s, o)| {
debug!("{e:?} {s:?} {o:?}"); debug!("{e:?} {s:?} {o:?}");
commands
.entity(e)
// TODO: Just move entities, do not de/re-spawn
.despawn_related::<ShapeBlocks>()
.with_related_entities::<BlockOf>(|parent| {
let mesh = visuals.mesh.clone();
let mat = visuals.material.clone();
#[rustfmt::skip]
let piece_positions: [RelativePosition;4] = match s {
Shape::O => [
(0,1).into(),(1,1).into(),
(0,0).into(),(1,0).into()
],
Shape::T => match o {
Orientation::Up => [
(0,1).into(),
(-1,0).into(),(0,0).into(),(1,0).into(),
],
Orientation::Down => [
(-1,0).into(),(0,0).into(),(1,0).into(),
(0,-1).into(),
],
Orientation::Right => [
(0,1).into(),
(0,0).into(), (1,0).into(),
(0,-1).into(),
],
Orientation::Left => [
(0,1).into(),
(-1,0).into(),(0,0).into(),
(0,-1).into(),
]
},
Shape::L => match o {
Orientation::Up => [
(0,1).into(),
(0,0).into(),
(0,-1).into(),(1,-1).into(),
],
Orientation::Down => [
(-1,1).into(),(0,1).into(),
(0,0).into(),
(0,-1).into(),
],
Orientation::Right => [
(-1,0).into(),(0,0).into(),(1,0).into(),
(-1,-1).into(),
],
Orientation::Left => [
(1,1).into(),
(-1,0).into(),(0,0).into(),(1,0).into(),
],
},
Shape::J => match o {
Orientation::Up => [
(0,1).into(),
(0,0).into(),
(-1,-1).into(),(0,-1).into(),
],
Orientation::Down => [
(0,1).into(),(1,1).into(),
(0,0).into(),
(0,-1).into(),
],
Orientation::Left => [
(-1,0).into(),(0,0).into(),(1,0).into(),
(1,-1).into(),
],
Orientation::Right => [
(-1,1).into(),
(-1,0).into(),(0,0).into(),(1,0).into()
],
},
Shape::S => match o {
Orientation::Up => [
(0,0).into(),(1,0).into(),
(-1,-1).into(),(0,-1).into(),
],
Orientation::Down => [
(0,1).into(),(1,1).into(),
(-1,0).into(),(0,0).into(),
],
Orientation::Right => [
(-1,1).into(),
(-1,0).into(),(0,0).into(),
(0,-1).into(),
],
Orientation::Left => [
(0,1).into(),
(0,0).into(),(1,0).into(),
(1,-1).into(),
],
},
Shape::Z => match o {
Orientation::Up => [
(-1,0).into(),(0,0).into(),
(0,-1).into(),(1,-1).into(),
],
Orientation::Down => [
(-1,1).into(),(0,1).into(),
(0,0).into(),(1,0).into(),
],
Orientation::Left => [
(1,1).into(),
(0,0).into(),(1,0).into(),
(0,-1).into(),
],
Orientation::Right => [
(0,1).into(),
(-1,0).into(),(0,0).into(),
(-1,-1).into(),
],
},
// TODO: This does not match tetris!
Shape::I => match o {
Orientation::Up => [
(0,2).into(),
(0,1).into(),
(0,0).into(),
(0,-1).into(),
],
Orientation::Down => [
(-1,2).into(),
(-1,1).into(),
(-1,0).into(),
(-1,-1).into(),
],
Orientation::Left => [
(-2,0).into(),(-1,0).into(),(0,0).into(),(1,0).into(),
],
Orientation::Right => [
(-2,1).into(),(-1,1).into(),(0,1).into(),(1,1).into(),
]
}
};
piece_positions.into_iter().for_each(|rp| {
parent.spawn((Mesh2d(mesh.clone()), MeshMaterial2d(mat.clone()), rp));
});
});
});
}
fn set_relative_piece_positions( let mesh = visuals.mesh.clone();
query: Query< let mat = visuals.material.clone();
(Entity, &RelativePosition, &BlockOf), let positions = block_positions(s, o);
Or<(Added<RelativePosition>, Changed<RelativePosition>)>,
>, if blocks.is_empty() {
gp: Query<&GridPosition>, commands
mut commands: Commands, .entity(e)
) { .with_related_entities::<BlockOf>(|parent| {
query.iter().for_each(|(e, rp, co)| { positions.into_iter().for_each(|rp| {
let parent_gp = gp.get(co.parent).unwrap(); parent.spawn((Mesh2d(mesh.clone()), MeshMaterial2d(mat.clone()), rp));
let gp: GridPosition = parent_gp.add_offset(rp); });
info!("Inserting {:?} for {:?} to {:?}", gp, rp, e); });
commands.entity(e).insert(gp); } else {
let mut p = positions.into_iter();
blocks.iter_mut().for_each(|mut rp| {
*rp = p.next().unwrap();
});
}
}); });
} }
@ -515,18 +524,37 @@ fn draw_grid(mut gizmos: Gizmos) {
.outer_edges(); .outer_edges();
} }
fn falling(mut query: Query<&mut GridPosition>) { fn falling(mut shape: Query<&mut GridPosition, With<Shape>>) {
query.iter_mut().for_each(|mut gp| { shape.iter_mut().for_each(|mut gp| {
let next = gp.move_down(); let next = gp.move_down();
if next != *gp { if next != *gp {
*gp = next; *gp = next;
} else { } else {
// Remove the falling component from this entity // TODO: What to do here??
} }
}); });
} }
// Re-implement parenting for movement, but on the grid structure
fn shape_block_movement(
shape: Query<
&GridPosition,
(
With<ShapeBlocks>,
Without<RelativePosition>,
),
>,
mut blocks: Query<(&mut GridPosition, &RelativePosition), With<BlockOf>>,
) {
shape.iter().for_each(|shape_gp| {
blocks.iter_mut().for_each(|(mut block_gp, block_rp)| {
*block_gp = shape_gp.add_offset(block_rp);
});
});
}
// Run condition that returns `true` every `n` seconds // Run condition that returns `true` every `n` seconds
// TODO: Update a resource with the current tick
fn clock_cycle(n: f32) -> impl FnMut(Res<Time>, Local<f32>) -> bool { fn clock_cycle(n: f32) -> impl FnMut(Res<Time>, Local<f32>) -> bool {
move |t: Res<Time>, mut buf: Local<f32>| -> bool { move |t: Res<Time>, mut buf: Local<f32>| -> bool {
*buf += t.delta_secs(); *buf += t.delta_secs();
@ -541,32 +569,44 @@ fn clock_cycle(n: f32) -> impl FnMut(Res<Time>, Local<f32>) -> bool {
/// Check if the active piece is about to collide with the ground /// Check if the active piece is about to collide with the ground
fn check_collision( fn check_collision(
active: Query<&GridPosition, With<RelativePosition>>, active: Query<(&GridPosition, Entity), With<RelativePosition>>,
shape: Single<Entity, With<Shape>>,
inactive: Query<&GridPosition, Without<RelativePosition>>, inactive: Query<&GridPosition, Without<RelativePosition>>,
mut commands: Commands,
) { ) {
// TODO: Easy optimizations // TODO: Easy optimizations
let hit = active.iter().any(|a| { let hit = active.iter().any(|(a, _e)| {
debug!("Checking: {:?}", a); debug!("Checking: {:?}", a);
// Check if active piece is at floor // Check if active shape is at floor
let hit_floor = a.y == 0; let hit_floor = a.y == 0;
// Check if active peice is near other pieces // Check if active peice is near other blocks
let hit_piece = inactive.iter().any(|b| { let hit_block = inactive.iter().any(|b| {
debug!("Checking against: {:?}", b); debug!("Checking against: {:?}", b);
a.is_colliding_with(b) a.is_colliding_with(b)
}); });
hit_floor || hit_piece hit_floor || hit_block
}); });
if hit { if false {
info!("hit!") info!("hit detected!");
// todo!("Do the thing!");
let blocks: Vec<Entity> = active
.iter()
.map(|(_, e)| commands.entity(e).remove::<RelativePosition>().id())
.collect();
debug_assert_eq!(blocks.len(), 4, "Shapes should have 4 blocks");
info!("De-relating blocks {:?} and shape {:?}", blocks, *shape);
commands
.entity(*shape)
.remove_related::<BlockOf>(blocks.as_slice())
.despawn();
} }
} }
fn add_piece( fn add_piece(mut commands: Commands) {
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));
} }

Loading…
Cancel
Save