diff --git a/src/bin/tetris.rs b/src/bin/tetris.rs index e897d2c..987ca2e 100644 --- a/src/bin/tetris.rs +++ b/src/bin/tetris.rs @@ -13,28 +13,6 @@ struct Position { pub z: u32, // render order } -impl Add for Position { - type Output = Self; - fn add(self, other: Self) -> Self { - Self { - x: self.x + other.x, - y: self.y + other.y, - z: self.z + other.z, - } - } -} - -impl Sub for Position { - type Output = Self; - fn sub(self, other: Self) -> Self { - Self { - x: self.x.saturating_sub(other.x), - y: self.y.saturating_sub(other.y), - z: self.z.saturating_sub(other.z), - } - } -} - #[derive(Component, Debug, Reflect)] struct Size { width: f32, @@ -50,17 +28,6 @@ impl Size { } } -fn spawn_tile(commands: &mut Commands, color: Color, size: f32, position: Position) -> Entity { - commands - .spawn(Sprite { - color, - ..Default::default() - }) - .insert(position) - .insert(Size::square(size)) - .id() -} - fn post_scale_tiles( window: Single<&Window>, matrix: Res, @@ -75,28 +42,6 @@ fn post_scale_tiles( } } -fn post_translate_tetrominos( - window: Single<&Window>, - matrix: Res, - mut q: Query<(&Position, &mut Transform), With>, -) { - // We subtract half the window width because our coordinate system starts at the bottom left, and - // Translation starts from the center. We then add half the size of a single tile, because we want - // our sprites bottom left corner to be at the bottom left of a tile, not the center. - fn convert(pos: f32, bound_window: f32, bound_game: f32) -> f32 { - let tile_size = bound_window / bound_game; - pos / bound_game * bound_window - (bound_window / 2.) + (tile_size / 2.) - } - - for (pos, mut transform) in q.iter_mut() { - transform.translation = Vec3::new( - convert(pos.x as f32, window.width(), matrix.width as f32), - convert(pos.y as f32, window.height(), matrix.height as f32), - pos.z as f32, - ); - } -} - fn post_translate_tiles( window: Single<&Window>, matrix: Res, @@ -119,16 +64,29 @@ fn post_translate_tiles( } } -#[derive(Component, Debug)] -struct TetrominoCoords([[u32; 2]; 4]); +fn translate_tetrominos( + tetrominos: Query<(&Tetromino, &mut Children)>, + mut positions: Query<&mut Position, With>, +) { + for (t, children) in tetrominos.iter() { + for child in children.iter() { + let mut p = positions.get_mut(*child).unwrap(); + p.x += t.pos.x; + p.y += t.pos.y; + } + } +} -const BRICK_I: TetrominoCoords = TetrominoCoords([[0, 0], [1, 0], [2, 0], [3, 0]]); -const BRICK_J: TetrominoCoords = TetrominoCoords([[0, 0], [1, 0], [2, 0], [2, 1]]); -const BRICK_L: TetrominoCoords = TetrominoCoords([[0, 0], [1, 0], [2, 0], [0, 1]]); -const BRICK_O: TetrominoCoords = TetrominoCoords([[0, 0], [1, 0], [0, 1], [1, 1]]); -const BRICK_S: TetrominoCoords = TetrominoCoords([[0, 0], [1, 0], [1, 1], [2, 1]]); -const BRICK_T: TetrominoCoords = TetrominoCoords([[0, 0], [1, 0], [2, 0], [1, 1]]); -const BRICK_Z: TetrominoCoords = TetrominoCoords([[0, 1], [1, 1], [1, 0], [2, 0]]); +#[derive(Component, Debug, Clone, Reflect)] +struct TetrominoKind([[u32; 2]; 4]); + +const BRICK_I: TetrominoKind = TetrominoKind([[0, 0], [1, 0], [2, 0], [3, 0]]); +const BRICK_J: TetrominoKind = TetrominoKind([[0, 0], [1, 0], [2, 0], [2, 1]]); +const BRICK_L: TetrominoKind = TetrominoKind([[0, 0], [1, 0], [2, 0], [0, 1]]); +const BRICK_O: TetrominoKind = TetrominoKind([[0, 0], [1, 0], [0, 1], [1, 1]]); +const BRICK_S: TetrominoKind = TetrominoKind([[0, 0], [1, 0], [1, 1], [2, 1]]); +const BRICK_T: TetrominoKind = TetrominoKind([[0, 0], [1, 0], [2, 0], [1, 1]]); +const BRICK_Z: TetrominoKind = TetrominoKind([[0, 1], [1, 1], [1, 0], [2, 0]]); enum RenderLayer { Background = 0, @@ -146,21 +104,47 @@ struct TileBundle { tile: Tile, } -fn spawn_tetromino(commands: &mut Commands, tetromino: TetrominoCoords, x: u32, y: u32) { - for coord in tetromino.0 { - commands.spawn(TileBundle { - position: Position { - x: coord[0] + x, - y: coord[1] + y, - z: RenderLayer::Brick as u32, - }, - size: Size::square(0.77), +fn spawn_tile(commands: &mut Commands, color: Color, size: f32, position: Position) -> Entity { + commands + .spawn(TileBundle { + position, + size: Size::square(size), sprite: Sprite { - color: Color::srgb(0.8, 1.0, 0.8), + color, ..Default::default() }, tile: Tile, - }); + }) + .id() +} + +#[derive(Component, Reflect)] +struct Tetromino { + pos: Position, + kind: TetrominoKind, +} + +fn spawn_tetromino(commands: &mut Commands, kind: TetrominoKind, x: u32, y: u32) { + let tetromino = commands + .spawn(Tetromino { + pos: Position { x, y, z: 0 }, + kind: kind.clone(), + }) + .insert((Transform::default(), Visibility::default())) + .id(); + + for coord in kind.0 { + let e = spawn_tile( + commands, + Color::srgb(0.3, 0.3, 0.8), + 0.9, + Position { + x: x + coord[0], + y: y + coord[1], + z: RenderLayer::Brick as u32, + }, + ); + commands.entity(e).set_parent(tetromino); } } @@ -178,11 +162,15 @@ fn main() { Startup, (init_singletons, init_window, init_tile_grid).chain(), ) - .add_systems(PostUpdate, (post_scale_tiles, post_translate_tiles)); + .add_systems( + PostUpdate, + (translate_tetrominos, post_scale_tiles, post_translate_tiles).chain(), + ); app.add_plugins(debug_plugin::debug_plugin); app.register_type::(); + app.register_type::(); app.register_type::(); // Run the app