Fixed line clearing bug

main
Elijah Voigt 1 day ago
parent 728e36171b
commit a6c96a6588

@ -1,3 +1,4 @@
#![feature(try_blocks)]
// Bevy basically forces "complex types" with Querys
#![allow(clippy::type_complexity)]
@ -27,39 +28,44 @@ fn main() {
.add_systems(Startup, (init_world, init_debug_ui, init_ui))
// Input and basic systems
.add_systems(
Update, (
Update,
(
kb_input.run_if(on_event::<KeyboardInput>),
toggle_state_visibility::<GameState>.run_if(state_changed::<GameState>),
)
),
)
.add_systems(
Update,
(
update_next_shapes.run_if(resource_changed::<ShapesBuffer>.or(resource_added::<ShapesBuffer>)),
add_piece.run_if(not(any_with_component::<Shape>)).after(update_next_shapes),
update_next_shapes
.run_if(resource_changed::<ShapesBuffer>.or(resource_added::<ShapesBuffer>)),
add_piece
.run_if(not(any_with_component::<Shape>))
.after(update_next_shapes),
update_shape_blocks
.run_if(any_component_added::<Shape>.or(any_component_changed::<Shape>)),
falling
.run_if(in_state(GameState::Falling))
.run_if(clock_cycle(1.0)),
update_position.run_if(any_component_changed::<GridPosition>),
deactivate_shape.run_if(any_component_removed::<Shape>),
check_line_removal,
// Clearing lines systems
clear_line.run_if(any_component_changed::<LineBlocks>),
adjust_block_lines.run_if(any_component_changed::<Line>).after(clear_line),
adjust_block_lines
.run_if(any_component_changed::<Line>)
.after(clear_line),
),
)
// UI systems
.add_systems(Update,
.add_systems(
Update,
(
sync_resource_to_ui::<ShapesBuffer>.run_if(resource_changed::<ShapesBuffer>),
sync_resource_to_ui::<Score>.run_if(resource_changed::<Score>),
sync_singleton_to_ui::<Shape>.run_if(any_component_changed::<Shape>),
sync_singleton_to_ui::<Orientation>.run_if(any_component_changed::<Orientation>),
)
),
)
.add_systems(Update, draw_grid)
.run();
@ -304,31 +310,25 @@ fn init_ui(mut commands: Commands) {
BackgroundColor(BLACK.into()),
))
.with_children(|parent| {
parent.spawn((
Node {
parent
.spawn((Node {
flex_direction: FlexDirection::Column,
align_items: AlignItems::Center,
..default()
},
)).with_children(|parent|{
},))
.with_children(|parent| {
parent.spawn(Text::new("Next:"));
parent.spawn((
Text::new("???"),
SyncResource::<ShapesBuffer>::default(),
));
parent.spawn((Text::new("???"), SyncResource::<ShapesBuffer>::default()));
});
parent.spawn((
Node {
parent
.spawn((Node {
flex_direction: FlexDirection::Column,
align_items: AlignItems::Center,
..default()
},
)).with_children(|parent|{
},))
.with_children(|parent| {
parent.spawn(Text::new("Score:"));
parent.spawn((
Text::new("???"),
SyncResource::<Score>::default(),
));
parent.spawn((Text::new("???"), SyncResource::<Score>::default()));
});
});
@ -563,7 +563,7 @@ fn update_shape_blocks(
visuals: Res<Visuals>,
) {
query.iter().for_each(|(e, s, o, center)| {
info!("Setting piece: {e:?} {o:?} {center:?}\n{}", s.as_ascii());
debug!("Setting piece: {e:?} {o:?} {center:?}\n{}", s.as_ascii());
if blocks.is_empty() {
let mesh = Mesh2d(visuals.mesh.clone());
@ -678,16 +678,17 @@ fn add_piece(mut commands: Commands, mut shapes: ResMut<ShapesBuffer>) {
/// When a line reaches 10 blocks, clear it
fn clear_line(
changed_lines: Query<Entity, Changed<LineBlocks>>,
mut lines: Query<(Entity, &LineBlocks, &mut Line)>,
mut lines: Query<&mut Line>,
line_blocks: Query<&LineBlocks>,
mut score: ResMut<Score>,
mut commands: Commands,
) {
let cleared_lines: Vec<usize> = changed_lines
let mut cleared_lines: Vec<usize> = changed_lines
.iter()
.filter_map(|e| lines.get(e).ok())
.filter_map(|e| try { (Some(e)?, line_blocks.get(e).ok()?, lines.get(e).ok()?) } )
.filter_map(|(e, lb, Line(i))| {
if lb.0.len() == 10 {
commands.entity(e).despawn_related::<LineBlocks>();
commands.entity(e).despawn_related::<LineBlocks>().insert(LineBlocks::default());
score.0 += 1;
info!("New score: {:?}", score.0);
Some(*i)
@ -695,23 +696,41 @@ fn clear_line(
None
}
})
.sorted()
.collect();
if !cleared_lines.is_empty() {
info!("Cleared lines: {:?}", cleared_lines);
for (idx, cleared_line_number) in cleared_lines.into_iter().sorted().enumerate() {
info!("Processing line {cleared_line_number} ({idx})");
let cleared_line_number = cleared_line_number - idx;
lines.iter_mut().sorted_by(|(_, _, i), (_, _, j)| i.0.cmp(&j.0)).for_each(|(_, _, mut l)| {
let dest = if l.0 > cleared_line_number {
l.0 - 1
} else if l.0 == cleared_line_number {
Y_MAX - 1
#[cfg(debug_assertions)]
{
debug_assert_eq!(lines.iter().count(), 20, "There should be 20 lines");
// Check that all line numbers are present
lines.iter().map(|Line(i)| i).sorted().enumerate().for_each(|(i, line_num)| {
debug_assert_eq!(i, *line_num, "Line numbers should match their sorted index");
});
}
let original_cleared_lines_len = cleared_lines.len();
// Iterate over all lines in reverse sorted order (largest to smallest)
lines
.iter_mut()
.sorted_by(|i, j| i.0.cmp(&j.0))
.rev()
.for_each(|mut l| {
// If the current index is in the set of cleared lines, move it to the top
// Otherwise, move it down by the number of cleared lines
if cleared_lines.contains(&l.0) {
// Move to the N-offset line number (top, top-1, etc)
let offset = original_cleared_lines_len - cleared_lines.len();
info!("Moving line {:?}->{:?}", l.0, Y_MAX - 1 - offset);
l.0 = Y_MAX - 1 - offset;
cleared_lines.pop();
} else {
l.0
};
info!("Moving line {:?} to {:?}", l, dest);
l.0 = dest;
info!("Moving line {:?}->{:?}", l.0, l.0 - cleared_lines.len());
l.0 -= cleared_lines.len();
}
});
}
}
@ -721,17 +740,6 @@ fn adjust_block_lines(
parent: Query<&LineBlocks>,
mut blocks: Query<&mut GridPosition>,
) {
#[cfg(debug_assertions)]
{
// Check that all line numbers are present
let expected_line_numbers = 0..Y_MAX;
let actual_line_numbers = query.iter().map(|(_, Line(i))| i).sorted();
query.iter().map(|(_, Line(i))| i).sorted().for_each(|i| info!("Line #: {i}"));
std::iter::zip(expected_line_numbers, actual_line_numbers).for_each(|(a, b)| {
debug_assert_eq!(a as usize, *b);
});
}
query.iter().for_each(|(e, Line(i))| {
parent.iter_descendants(e).for_each(|block| {
if let Ok(mut gp) = blocks.get_mut(block) {
@ -767,7 +775,7 @@ fn movement(
Movement::Right => (center.with_offset(1, 0), *this_shape),
Movement::Rotate => (Ok(*center), this_shape.rotated()),
};
info!(
debug!(
"Proposed change: {:?}\n{}",
new_center,
new_shape.as_ascii()
@ -819,6 +827,14 @@ fn movement(
}
}
fn check_line_removal(
mut events: RemovedComponents<Line>,
) {
events.read().for_each(|e| {
info!("Line entity {:?} removed", e);
});
}
// TODO: Just despawn?
fn deactivate_shape(
mut events: RemovedComponents<Shape>,

Loading…
Cancel
Save