From 90a6181e2282900d91712c0c4453933ab16ec945 Mon Sep 17 00:00:00 2001 From: Elijah Voigt Date: Fri, 24 Oct 2025 22:40:59 -0700 Subject: [PATCH] We did it chat. We got clearing lines working --- Cargo.toml | 1 + src/bin/tetris/main.rs | 71 +++++++++++++++++++++++++++++++++--------- 2 files changed, 58 insertions(+), 14 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index cd4099c..ff1f803 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ path = "examples/demos/parallax3d.rs" hide_debug = [] [dependencies] +itertools = "*" thiserror = "2.0.12" [dependencies.serde] diff --git a/src/bin/tetris/main.rs b/src/bin/tetris/main.rs index 8c5d16f..3236638 100644 --- a/src/bin/tetris/main.rs +++ b/src/bin/tetris/main.rs @@ -1,10 +1,9 @@ // Bevy basically forces "complex types" with Querys #![allow(clippy::type_complexity)] +use itertools::Itertools; use games::*; -// *TODO: Detect when piece is going to go out of bounds and restirct parent from moving there -// TODO: When shape touches the rest of the pieces, re-parent to line entity // TODO: When line is "full" (has 10 children) clear line and add to score fn main() { @@ -31,6 +30,7 @@ fn main() { update_position, add_piece.run_if(not(any_with_component::)), clear_line.run_if(any_component_changed::), + adjust_block_lines.run_if(any_component_changed::), ), ) .add_systems(Update, draw_grid) @@ -58,7 +58,7 @@ struct ShapeBlock { } // The blocks making up this shape -#[derive(Component, Default)] +#[derive(Component, Default, Debug)] #[relationship_target(relationship = LineBlock)] struct LineBlocks(Vec); @@ -72,8 +72,8 @@ struct LineBlock { } // A line holds up to 10 blocks before being cleared -#[derive(Component, Debug)] -struct Line(u8); +#[derive(Component, Debug, Clone, Copy)] +struct Line(usize); // Just marks a block either of a shape or line #[derive(Component, Debug)] @@ -570,15 +570,53 @@ fn add_piece(mut commands: Commands) { /// When a line reaches 10 blocks, clear it fn clear_line( - lines: Query<(Entity, &LineBlocks), (With, Changed)>, + changed_lines: Query>, + mut lines: Query<(Entity, &LineBlocks, &mut Line)>, mut commands: Commands, ) { - lines.iter().for_each(|(e, lb)| { - if lb.0.len() == 10 { - commands.entity(e).despawn_related::(); - // TODO: re-parent all blocks above this to the next line down - // TODO: Parent blocks to lines for movement - } + let cleared_lines: Vec = changed_lines + .iter() + .filter_map(|e| lines.get(e).ok()) + .filter_map(|(e, lb, Line(i))| { + if lb.0.len() == 10 { + commands.entity(e).despawn_related::(); + Some(*i) + } else { + None + } + }) + .collect(); + + 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().for_each(|(_, _, mut l)| { + let dest = if l.0 > cleared_line_number { + l.0 - 1 + } else if l.0 == cleared_line_number { + (Y_MAX - (idx + 1) as u32) as usize + } else { + l.0 + }; + info!("Moving line {:?} to {:?}", l, dest); + l.0 = dest; + }); + } +} + +fn adjust_block_lines( + query: Query<(Entity, &Line), Changed>, + parent: Query<&LineBlocks>, + mut blocks: Query<&mut GridPosition>, +) { + query.iter().for_each(|(e, Line(i))| { + parent.iter_descendants(e).for_each(|block| { + if let Ok(mut gp) = blocks.get_mut(block) { + gp.y = *i as u32; + } + }); }); } @@ -670,8 +708,13 @@ fn deactive_shape( ) { parent.iter_descendants(trigger.target()).for_each(|block| { let GridPosition { y, .. } = grid_positions.get(block).unwrap(); - let parent_line = lines.iter().find_map(|(e, Line(i))| (*y == *i as u32).then_some(e)).unwrap(); - commands.entity(parent_line).add_one_related::(block); + let parent_line = lines + .iter() + .find_map(|(e, Line(i))| (*y == *i as u32).then_some(e)) + .unwrap(); + commands + .entity(parent_line) + .add_one_related::(block); }); commands.entity(trigger.target()).despawn(); }