From b51884ac698d64bc3d62a052841b4982b9aa0385 Mon Sep 17 00:00:00 2001 From: Elijah Voigt Date: Sat, 11 Oct 2025 21:03:00 -0700 Subject: [PATCH] Moved away from childof relationship! Instead of using ChildOf, which has Transform implications, we created our own relationship: ShapeBlocks(Vec) <-> BlockOf { parent: Entity } This relationship just informs how to place blocks with a RelativePosition near their GridPosition parents without having to deal with the Transform of the parent. --- src/bin/tetris/main.rs | 101 ++++++++++++++++++++++++++++++++--------- 1 file changed, 80 insertions(+), 21 deletions(-) diff --git a/src/bin/tetris/main.rs b/src/bin/tetris/main.rs index 5121c86..c32a460 100644 --- a/src/bin/tetris/main.rs +++ b/src/bin/tetris/main.rs @@ -37,6 +37,8 @@ fn main() { ), sync_singleton_to_ui::.run_if(any_component_changed::), sync_singleton_to_ui::.run_if(any_component_changed::), + check_collision.run_if(any_component_changed::), + add_piece.run_if(not(any_with_component::)), ), ) .add_systems(Update, draw_grid) @@ -45,6 +47,10 @@ fn main() { const SCALE: f32 = 30.0; +// Declare the size of the play area +const X_MAX: u32 = 10; +const Y_MAX: u32 = 20; + /// A shape, e.g., the long piece #[derive(Component, Debug, Default)] enum Shape { @@ -72,11 +78,21 @@ impl Display for Shape { } } +// The blocks making up this shape +#[derive(Component)] +#[relationship_target(relationship = BlockOf)] +struct ShapeBlocks(Vec); + /// A part of a piece, i.e., a single square of a piece #[derive(Component, Debug)] -struct ShapePiece; +#[relationship(relationship_target = ShapeBlocks)] +struct BlockOf { + #[relationship] + parent: Entity, +} #[derive(Component, Debug)] +#[require(GridPosition)] struct RelativePosition { x: i8, y: i8, @@ -91,14 +107,14 @@ impl From<(i8, i8)> for RelativePosition { #[derive(Component, Debug, Clone, Copy, PartialEq)] #[require(Transform, Visibility)] struct GridPosition { - x: usize, - y: usize, + x: u32, + y: u32, } impl GridPosition { fn move_up(&self) -> Self { Self { - y: if self.y + 1 < 20 { + y: if self.y + 1 < Y_MAX { self.y.saturating_add(1) } else { self.y @@ -123,7 +139,7 @@ impl GridPosition { fn move_right(&mut self) -> Self { Self { - x: if self.x + 1 < 10 { + x: if self.x + 1 < X_MAX { self.x.saturating_add(1) } else { self.x @@ -131,11 +147,23 @@ impl GridPosition { y: self.y, } } + + fn is_colliding_with(&self, other: &Self) -> bool { + self.x == other.x && self.y + 1 == other.y + } + + fn add_offset(&self, RelativePosition { x: x1, y: y1 }: &RelativePosition) -> Self { + info!("{} + {}, {} + {}", self.x, *x1 as i32, self.y, *y1 as i32); + GridPosition { + x: self.x.checked_add_signed(*x1 as i32).unwrap(), + y: self.y.checked_add_signed(*y1 as i32).unwrap(), + } + } } impl Default for GridPosition { fn default() -> Self { - GridPosition { x: 5, y: 20 } + GridPosition { x: 5, y: Y_MAX } } } @@ -154,8 +182,8 @@ impl From<&GridPosition> for Vec3 { } } -impl From<(usize, usize)> for GridPosition { - fn from((x, y): (usize, usize)) -> GridPosition { +impl From<(u32, u32)> for GridPosition { + fn from((x, y): (u32, u32)) -> GridPosition { GridPosition { x, y } } } @@ -242,8 +270,6 @@ fn init_pieces( }), mesh: meshes.add(Rectangle::new(SCALE, SCALE)), }); - - commands.spawn((Orientation::default(), GridPosition::default(), Shape::T)); } fn init_debug_ui( @@ -273,8 +299,9 @@ fn set_piece( debug!("{e:?} {s:?} {o:?}"); commands .entity(e) - .despawn_related::() - .with_children(|parent| { + // TODO: Just move entities, do not de/re-spawn + .despawn_related::() + .with_related_entities::(|parent| { let mesh = visuals.mesh.clone(); let mat = visuals.material.clone(); @@ -416,17 +443,17 @@ fn set_piece( fn set_relative_piece_positions( query: Query< - (Entity, &RelativePosition), + (Entity, &RelativePosition, &BlockOf), Or<(Added, Changed)>, >, + gp: Query<&GridPosition>, mut commands: Commands, ) { - query.iter().for_each(|(e, rp)| { - commands.entity(e).insert(Transform::from_xyz( - (rp.x as f32) * SCALE, - (rp.y as f32) * SCALE, - 0.0, - )); + query.iter().for_each(|(e, rp, co)| { + let parent_gp = gp.get(co.parent).unwrap(); + let gp: GridPosition = parent_gp.add_offset(rp); + info!("Inserting {:?} for {:?} to {:?}", gp, rp, e); + commands.entity(e).insert(gp); }); } @@ -481,14 +508,14 @@ fn draw_grid(mut gizmos: Gizmos) { gizmos .grid_2d( Isometry2d::IDENTITY, - UVec2::new(10, 20), + UVec2::new(X_MAX, Y_MAX), Vec2::new(SCALE, SCALE), GREEN, ) .outer_edges(); } -fn falling(mut query: Query<&mut GridPosition, With>) { +fn falling(mut query: Query<&mut GridPosition>) { query.iter_mut().for_each(|mut gp| { let next = gp.move_down(); if next != *gp { @@ -511,3 +538,35 @@ fn clock_cycle(n: f32) -> impl FnMut(Res