From 675cff23efb0e34c249f74c9d333f4f3ec2790d4 Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Sat, 19 Mar 2022 18:10:38 -0400 Subject: [PATCH 1/7] Move Velocity into its own component --- examples/game/breakout.rs | 44 +++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/examples/game/breakout.rs b/examples/game/breakout.rs index bd420df48b91b..8cd67fa4c03c2 100644 --- a/examples/game/breakout.rs +++ b/examples/game/breakout.rs @@ -54,7 +54,7 @@ fn main() { .with_run_criteria(FixedTimestep::step(TIME_STEP as f64)) .with_system(paddle_movement_system) .with_system(ball_collision_system) - .with_system(ball_movement_system), + .with_system(apply_velocity_system), ) .add_system(scoreboard_system) .add_system(bevy::input::system::exit_on_esc_system) @@ -67,8 +67,12 @@ struct Paddle { } #[derive(Component)] -struct Ball { - velocity: Vec3, +struct Ball; + +#[derive(Component)] +struct Velocity { + x: f32, + y: f32, } #[derive(Component)] @@ -107,6 +111,8 @@ fn setup(mut commands: Commands, asset_server: Res) { }) .insert(Collider::Paddle); // ball + let ball_velocity = BALL_SPEED * INITIAL_BALL_DIRECTION.extend(0.0).normalize(); + commands .spawn_bundle(SpriteBundle { transform: Transform { @@ -120,9 +126,10 @@ fn setup(mut commands: Commands, asset_server: Res) { }, ..default() }) - .insert(Ball { - // We can create a velocity by multiplying our speed by a normalized direction. - velocity: BALL_SPEED * INITIAL_BALL_DIRECTION.extend(0.0).normalize(), + .insert(Ball) + .insert(Velocity { + x: ball_velocity.x, + y: ball_velocity.y, }); // scoreboard commands.spawn_bundle(TextBundle { @@ -272,9 +279,11 @@ fn paddle_movement_system( translation.x = translation.x.min(PADDLE_BOUNDS).max(-PADDLE_BOUNDS); } -fn ball_movement_system(mut ball_query: Query<(&Ball, &mut Transform)>) { - let (ball, mut transform) = ball_query.single_mut(); - transform.translation += ball.velocity * TIME_STEP; +fn apply_velocity_system(mut query: Query<(&mut Transform, &Velocity)>) { + for (mut transform, velocity) in query.iter_mut() { + transform.translation.x += velocity.x * TIME_STEP; + transform.translation.y += velocity.y * TIME_STEP; + } } fn scoreboard_system(scoreboard: Res, mut query: Query<&mut Text>) { @@ -285,12 +294,11 @@ fn scoreboard_system(scoreboard: Res, mut query: Query<&mut Text>) { fn ball_collision_system( mut commands: Commands, mut scoreboard: ResMut, - mut ball_query: Query<(&mut Ball, &Transform)>, + mut ball_query: Query<(&mut Velocity, &Transform), With>, collider_query: Query<(Entity, &Collider, &Transform)>, ) { - let (mut ball, ball_transform) = ball_query.single_mut(); + let (mut ball_velocity, ball_transform) = ball_query.single_mut(); let ball_size = ball_transform.scale.truncate(); - let velocity = &mut ball.velocity; // check collision with walls for (collider_entity, collider, transform) in collider_query.iter() { @@ -314,21 +322,21 @@ fn ball_collision_system( // only reflect if the ball's velocity is going in the opposite direction of the // collision match collision { - Collision::Left => reflect_x = velocity.x > 0.0, - Collision::Right => reflect_x = velocity.x < 0.0, - Collision::Top => reflect_y = velocity.y < 0.0, - Collision::Bottom => reflect_y = velocity.y > 0.0, + Collision::Left => reflect_x = ball_velocity.x > 0.0, + Collision::Right => reflect_x = ball_velocity.x < 0.0, + Collision::Top => reflect_y = ball_velocity.y < 0.0, + Collision::Bottom => reflect_y = ball_velocity.y > 0.0, Collision::Inside => { /* do nothing */ } } // reflect velocity on the x-axis if we hit something on the x-axis if reflect_x { - velocity.x = -velocity.x; + ball_velocity.x = -ball_velocity.x; } // reflect velocity on the y-axis if we hit something on the y-axis if reflect_y { - velocity.y = -velocity.y; + ball_velocity.y = -ball_velocity.y; } // break if this collide is on a solid, otherwise continue check whether a solid is From 4abd868da0aeafc73f4d29b4282d856c7ce5555e Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Sat, 19 Mar 2022 18:12:01 -0400 Subject: [PATCH 2/7] Don't store paddle speed in the Paddle component --- examples/game/breakout.rs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/examples/game/breakout.rs b/examples/game/breakout.rs index 8cd67fa4c03c2..601728cb71679 100644 --- a/examples/game/breakout.rs +++ b/examples/game/breakout.rs @@ -62,9 +62,7 @@ fn main() { } #[derive(Component)] -struct Paddle { - speed: f32, -} +struct Paddle; #[derive(Component)] struct Ball; @@ -106,9 +104,7 @@ fn setup(mut commands: Commands, asset_server: Res) { }, ..default() }) - .insert(Paddle { - speed: PADDLE_SPEED, - }) + .insert(Paddle) .insert(Collider::Paddle); // ball let ball_velocity = BALL_SPEED * INITIAL_BALL_DIRECTION.extend(0.0).normalize(); @@ -260,9 +256,9 @@ fn setup(mut commands: Commands, asset_server: Res) { fn paddle_movement_system( keyboard_input: Res>, - mut query: Query<(&Paddle, &mut Transform)>, + mut query: Query<&mut Transform, With>, ) { - let (paddle, mut transform) = query.single_mut(); + let mut transform = query.single_mut(); let mut direction = 0.0; if keyboard_input.pressed(KeyCode::Left) { direction -= 1.0; @@ -274,7 +270,7 @@ fn paddle_movement_system( let translation = &mut transform.translation; // move the paddle horizontally - translation.x += direction * paddle.speed * TIME_STEP; + translation.x += direction * 400.0 * TIME_STEP; // bound the paddle within the walls translation.x = translation.x.min(PADDLE_BOUNDS).max(-PADDLE_BOUNDS); } From b26cab2ff309577cb7bbaa1cc72e601f9360f5d7 Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Sat, 19 Mar 2022 18:19:06 -0400 Subject: [PATCH 3/7] Split Collider enum component into two simple marker components --- examples/game/breakout.rs | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/examples/game/breakout.rs b/examples/game/breakout.rs index 601728cb71679..04d9fa820a64c 100644 --- a/examples/game/breakout.rs +++ b/examples/game/breakout.rs @@ -74,11 +74,10 @@ struct Velocity { } #[derive(Component)] -enum Collider { - Solid, - Scorable, - Paddle, -} +struct Collider; + +#[derive(Component)] +struct Brick; struct Scoreboard { score: usize, @@ -105,7 +104,7 @@ fn setup(mut commands: Commands, asset_server: Res) { ..default() }) .insert(Paddle) - .insert(Collider::Paddle); + .insert(Collider); // ball let ball_velocity = BALL_SPEED * INITIAL_BALL_DIRECTION.extend(0.0).normalize(); @@ -176,7 +175,7 @@ fn setup(mut commands: Commands, asset_server: Res) { }, ..default() }) - .insert(Collider::Solid); + .insert(Collider); // right commands .spawn_bundle(SpriteBundle { @@ -191,7 +190,7 @@ fn setup(mut commands: Commands, asset_server: Res) { }, ..default() }) - .insert(Collider::Solid); + .insert(Collider); // bottom commands .spawn_bundle(SpriteBundle { @@ -206,7 +205,7 @@ fn setup(mut commands: Commands, asset_server: Res) { }, ..default() }) - .insert(Collider::Solid); + .insert(Collider); // top commands .spawn_bundle(SpriteBundle { @@ -221,7 +220,7 @@ fn setup(mut commands: Commands, asset_server: Res) { }, ..default() }) - .insert(Collider::Solid); + .insert(Collider); // Add bricks let bricks_width = BRICK_COLUMNS as f32 * (BRICK_SIZE.x + BRICK_SPACING) - BRICK_SPACING; @@ -249,7 +248,8 @@ fn setup(mut commands: Commands, asset_server: Res) { }, ..default() }) - .insert(Collider::Scorable); + .insert(Collider) + .insert(Brick); } } } @@ -291,13 +291,13 @@ fn ball_collision_system( mut commands: Commands, mut scoreboard: ResMut, mut ball_query: Query<(&mut Velocity, &Transform), With>, - collider_query: Query<(Entity, &Collider, &Transform)>, + collider_query: Query<(Entity, &Transform, Option<&Brick>), With>, ) { let (mut ball_velocity, ball_transform) = ball_query.single_mut(); let ball_size = ball_transform.scale.truncate(); // check collision with walls - for (collider_entity, collider, transform) in collider_query.iter() { + for (collider_entity, transform, maybe_brick) in collider_query.iter() { let collision = collide( ball_transform.translation, ball_size, @@ -305,8 +305,8 @@ fn ball_collision_system( transform.scale.truncate(), ); if let Some(collision) = collision { - // scorable colliders should be despawned and increment the scoreboard on collision - if let Collider::Scorable = *collider { + // Bricks should be despawned and increment the scoreboard on collision + if maybe_brick.is_some() { scoreboard.score += 1; commands.entity(collider_entity).despawn(); } @@ -334,12 +334,6 @@ fn ball_collision_system( if reflect_y { ball_velocity.y = -ball_velocity.y; } - - // break if this collide is on a solid, otherwise continue check whether a solid is - // also in collision - if let Collider::Solid = *collider { - break; - } } } } From d269e0d09e6a9b8131d8d28952dae283b861b6cd Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Sat, 19 Mar 2022 18:19:52 -0400 Subject: [PATCH 4/7] Merge constants PR in --- examples/game/breakout.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/game/breakout.rs b/examples/game/breakout.rs index 04d9fa820a64c..f3e473c9ce7eb 100644 --- a/examples/game/breakout.rs +++ b/examples/game/breakout.rs @@ -79,6 +79,7 @@ struct Collider; #[derive(Component)] struct Brick; +// This resource tracks the game's score struct Scoreboard { score: usize, } @@ -270,7 +271,7 @@ fn paddle_movement_system( let translation = &mut transform.translation; // move the paddle horizontally - translation.x += direction * 400.0 * TIME_STEP; + translation.x += direction * PADDLE_SPEED * TIME_STEP; // bound the paddle within the walls translation.x = translation.x.min(PADDLE_BOUNDS).max(-PADDLE_BOUNDS); } From d531fca7d791654baa869d34541170542b9ef844 Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Wed, 23 Mar 2022 13:19:54 -0400 Subject: [PATCH 5/7] Fix up ball velocity --- examples/game/breakout.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/game/breakout.rs b/examples/game/breakout.rs index f3e473c9ce7eb..24e86766904d4 100644 --- a/examples/game/breakout.rs +++ b/examples/game/breakout.rs @@ -107,7 +107,7 @@ fn setup(mut commands: Commands, asset_server: Res) { .insert(Paddle) .insert(Collider); // ball - let ball_velocity = BALL_SPEED * INITIAL_BALL_DIRECTION.extend(0.0).normalize(); + let ball_velocity = INITIAL_BALL_DIRECTION.normalize() * BALL_SPEED; commands .spawn_bundle(SpriteBundle { From a53a0742d67892b0ad708b549dce7210f07a16d0 Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Wed, 23 Mar 2022 14:22:11 -0400 Subject: [PATCH 6/7] Pedantic component ordering :D --- examples/game/breakout.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/examples/game/breakout.rs b/examples/game/breakout.rs index 24e86766904d4..d8b7a868a3228 100644 --- a/examples/game/breakout.rs +++ b/examples/game/breakout.rs @@ -92,7 +92,9 @@ fn setup(mut commands: Commands, asset_server: Res) { commands.spawn_bundle(UiCameraBundle::default()); // paddle commands - .spawn_bundle(SpriteBundle { + .spawn() + .insert(Paddle) + .insert_bundle(SpriteBundle { transform: Transform { translation: Vec3::new(0.0, PADDLE_HEIGHT, 0.0), scale: PADDLE_SIZE, @@ -104,13 +106,14 @@ fn setup(mut commands: Commands, asset_server: Res) { }, ..default() }) - .insert(Paddle) .insert(Collider); // ball let ball_velocity = INITIAL_BALL_DIRECTION.normalize() * BALL_SPEED; commands - .spawn_bundle(SpriteBundle { + .spawn() + .insert(Ball) + .insert_bundle(SpriteBundle { transform: Transform { scale: BALL_SIZE, translation: BALL_STARTING_POSITION, @@ -122,7 +125,6 @@ fn setup(mut commands: Commands, asset_server: Res) { }, ..default() }) - .insert(Ball) .insert(Velocity { x: ball_velocity.x, y: ball_velocity.y, @@ -237,7 +239,9 @@ fn setup(mut commands: Commands, asset_server: Res) { ) + bricks_offset; // brick commands - .spawn_bundle(SpriteBundle { + .spawn() + .insert(Brick) + .insert_bundle(SpriteBundle { sprite: Sprite { color: BRICK_COLOR, ..default() @@ -249,8 +253,7 @@ fn setup(mut commands: Commands, asset_server: Res) { }, ..default() }) - .insert(Collider) - .insert(Brick); + .insert(Collider); } } } From b50e03f836209224a8f32c113dd2a7f98921a56a Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Wed, 23 Mar 2022 14:25:15 -0400 Subject: [PATCH 7/7] Swap Velocity to a Vec2 --- examples/game/breakout.rs | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/examples/game/breakout.rs b/examples/game/breakout.rs index d8b7a868a3228..b7afd4db03771 100644 --- a/examples/game/breakout.rs +++ b/examples/game/breakout.rs @@ -68,10 +68,7 @@ struct Paddle; struct Ball; #[derive(Component)] -struct Velocity { - x: f32, - y: f32, -} +struct Velocity(Vec2); #[derive(Component)] struct Collider; @@ -125,10 +122,7 @@ fn setup(mut commands: Commands, asset_server: Res) { }, ..default() }) - .insert(Velocity { - x: ball_velocity.x, - y: ball_velocity.y, - }); + .insert(Velocity(ball_velocity)); // scoreboard commands.spawn_bundle(TextBundle { text: Text { @@ -281,8 +275,8 @@ fn paddle_movement_system( fn apply_velocity_system(mut query: Query<(&mut Transform, &Velocity)>) { for (mut transform, velocity) in query.iter_mut() { - transform.translation.x += velocity.x * TIME_STEP; - transform.translation.y += velocity.y * TIME_STEP; + transform.translation.x += velocity.0.x * TIME_STEP; + transform.translation.y += velocity.0.y * TIME_STEP; } } @@ -322,21 +316,21 @@ fn ball_collision_system( // only reflect if the ball's velocity is going in the opposite direction of the // collision match collision { - Collision::Left => reflect_x = ball_velocity.x > 0.0, - Collision::Right => reflect_x = ball_velocity.x < 0.0, - Collision::Top => reflect_y = ball_velocity.y < 0.0, - Collision::Bottom => reflect_y = ball_velocity.y > 0.0, + Collision::Left => reflect_x = ball_velocity.0.x > 0.0, + Collision::Right => reflect_x = ball_velocity.0.x < 0.0, + Collision::Top => reflect_y = ball_velocity.0.y < 0.0, + Collision::Bottom => reflect_y = ball_velocity.0.y > 0.0, Collision::Inside => { /* do nothing */ } } // reflect velocity on the x-axis if we hit something on the x-axis if reflect_x { - ball_velocity.x = -ball_velocity.x; + ball_velocity.0.x = -ball_velocity.0.x; } // reflect velocity on the y-axis if we hit something on the y-axis if reflect_y { - ball_velocity.y = -ball_velocity.y; + ball_velocity.0.y = -ball_velocity.0.y; } } }