//! A simplified implementation of the classic game "Breakout". use bevy::{ prelude::*, }; // These constants are defined in `Transform` units. // Using the default 2D camera they correspond 1:1 with screen pixels. const GAP_BETWEEN_PADDLE_AND_FLOOR: f32 = 60.0; const LEFT_WALL: f32 = -450.; const RIGHT_WALL: f32 = 450.; // y coordinates const BOTTOM_WALL: f32 = -300.; const TOP_WALL: f32 = 300.; const PARTICLE_SIZE: Vec2 = Vec2::new(10., 10.); // These values are exact const GAP_BETWEEN_PADDLE_AND_BRICKS: f32 = 270.0; const GAP_BETWEEN_BRICKS: f32 = 5.0; // These values are lower bounds, as the number of bricks is computed const GAP_BETWEEN_BRICKS_AND_CEILING: f32 = 20.0; const GAP_BETWEEN_BRICKS_AND_SIDES: f32 = 20.0; const BACKGROUND_COLOR: Color = Color::rgb(0.9, 0.9, 0.9); const BRICK_COLOR: Color = Color::rgb(0.5, 0.5, 1.0); fn main() { App::new() .add_plugins(DefaultPlugins) .insert_resource(ClearColor(BACKGROUND_COLOR)) .add_startup_system(setup) .add_system(bevy::window::close_on_esc) .run(); } #[derive(Component)] struct Brick; // Add the game's entities to our world fn setup( mut commands: Commands, ) { // Camera commands.spawn(Camera2dBundle::default()); // Paddle let paddle_y = BOTTOM_WALL + GAP_BETWEEN_PADDLE_AND_FLOOR; // Bricks // Negative scales result in flipped sprites / meshes, // which is definitely not what we want here assert!(PARTICLE_SIZE.x > 0.0); assert!(PARTICLE_SIZE.y > 0.0); let total_width_of_bricks = (RIGHT_WALL - LEFT_WALL) - 2. * GAP_BETWEEN_BRICKS_AND_SIDES; let bottom_edge_of_bricks = paddle_y + GAP_BETWEEN_PADDLE_AND_BRICKS; let total_height_of_bricks = TOP_WALL - bottom_edge_of_bricks - GAP_BETWEEN_BRICKS_AND_CEILING; assert!(total_width_of_bricks > 0.0); assert!(total_height_of_bricks > 0.0); // Given the space available, compute how many rows and columns of bricks we can fit let n_columns = (total_width_of_bricks / (PARTICLE_SIZE.x + GAP_BETWEEN_BRICKS)).floor() as usize; let n_rows = (total_height_of_bricks / (PARTICLE_SIZE.y + GAP_BETWEEN_BRICKS)).floor() as usize; let n_vertical_gaps = n_columns - 1; // Because we need to round the number of columns, // the space on the top and sides of the bricks only captures a lower bound, not an exact value let center_of_bricks = (LEFT_WALL + RIGHT_WALL) / 2.0; let left_edge_of_bricks = center_of_bricks // Space taken up by the bricks - (n_columns as f32 / 2.0 * PARTICLE_SIZE.x) // Space taken up by the gaps - n_vertical_gaps as f32 / 2.0 * GAP_BETWEEN_BRICKS; // In Bevy, the `translation` of an entity describes the center point, // not its bottom-left corner let offset_x = left_edge_of_bricks + PARTICLE_SIZE.x / 2.; let offset_y = bottom_edge_of_bricks + PARTICLE_SIZE.y / 2.; for row in 0..n_rows { for column in 0..n_columns { let brick_position = Vec2::new( offset_x + column as f32 * (PARTICLE_SIZE.x + GAP_BETWEEN_BRICKS), offset_y + row as f32 * (PARTICLE_SIZE.y + GAP_BETWEEN_BRICKS), ); // brick commands.spawn(( SpriteBundle { sprite: Sprite { color: BRICK_COLOR, ..default() }, transform: Transform { translation: brick_position.extend(0.0), scale: Vec3::new(PARTICLE_SIZE.x, PARTICLE_SIZE.y, 1.0), ..default() }, ..default() }, Brick, )); } } }