Update breakout to use Required Components (#16577)

# Objective

This PR update breakout to use the new 0.15 Required Component feature
instead of the Bundle.
Add more information in the comment about where to find more info about
Required Components.

## Solution

Replace `#[derive(Bundle)]` with a new Wall component and `#[require()]`
Macro to include the other components.

## Testing

Tested with `cargo test` as well tested the game manually with `cargo
run --example breakout` It looks to me that it works like it used to
before the changes. Tested on Arch Linux, Wayland

---------

Co-authored-by: Arnav Mummineni <45217840+RCoder01@users.noreply.github.com>
Co-authored-by: Joona Aalto <jondolf.dev@gmail.com>
This commit is contained in:
Emad Ali 2024-12-07 01:21:26 +01:00 committed by GitHub
parent f5de3f08fb
commit 48fb4aa6d5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -89,9 +89,6 @@ struct Ball;
#[derive(Component, Deref, DerefMut)] #[derive(Component, Deref, DerefMut)]
struct Velocity(Vec2); struct Velocity(Vec2);
#[derive(Component)]
struct Collider;
#[derive(Event, Default)] #[derive(Event, Default)]
struct CollisionEvent; struct CollisionEvent;
@ -101,15 +98,14 @@ struct Brick;
#[derive(Resource, Deref)] #[derive(Resource, Deref)]
struct CollisionSound(Handle<AudioSource>); struct CollisionSound(Handle<AudioSource>);
// This bundle is a collection of the components that define a "wall" in our game // Default must be implemented to define this as a required component for the Wall component below
#[derive(Bundle)] #[derive(Component, Default)]
struct WallBundle { struct Collider;
// You can nest bundles inside of other bundles like this
// Allowing you to compose their functionality // This is a collection of the components that define a "Wall" in our game
sprite: Sprite, #[derive(Component)]
transform: Transform, #[require(Sprite, Transform, Collider)]
collider: Collider, struct Wall;
}
/// Which side of the arena is this wall located on? /// Which side of the arena is this wall located on?
enum WallLocation { enum WallLocation {
@ -149,13 +145,15 @@ impl WallLocation {
} }
} }
impl WallBundle { impl Wall {
// This "builder method" allows us to reuse logic across our wall entities, // This "builder method" allows us to reuse logic across our wall entities,
// making our code easier to read and less prone to bugs when we change the logic // making our code easier to read and less prone to bugs when we change the logic
fn new(location: WallLocation) -> WallBundle { // Notice the use of Sprite and Transform alongside Wall, overwriting the default values defined for the required components
WallBundle { fn new(location: WallLocation) -> (Wall, Sprite, Transform) {
sprite: Sprite::from_color(WALL_COLOR, Vec2::ONE), (
transform: Transform { Wall,
Sprite::from_color(WALL_COLOR, Vec2::ONE),
Transform {
// We need to convert our Vec2 into a Vec3, by giving it a z-coordinate // We need to convert our Vec2 into a Vec3, by giving it a z-coordinate
// This is used to determine the order of our sprites // This is used to determine the order of our sprites
translation: location.position().extend(0.0), translation: location.position().extend(0.0),
@ -165,8 +163,7 @@ impl WallBundle {
scale: location.size().extend(1.0), scale: location.size().extend(1.0),
..default() ..default()
}, },
collider: Collider, )
}
} }
} }
@ -242,10 +239,10 @@ fn setup(
)); ));
// Walls // Walls
commands.spawn(WallBundle::new(WallLocation::Left)); commands.spawn(Wall::new(WallLocation::Left));
commands.spawn(WallBundle::new(WallLocation::Right)); commands.spawn(Wall::new(WallLocation::Right));
commands.spawn(WallBundle::new(WallLocation::Bottom)); commands.spawn(Wall::new(WallLocation::Bottom));
commands.spawn(WallBundle::new(WallLocation::Top)); commands.spawn(Wall::new(WallLocation::Top));
// Bricks // Bricks
let total_width_of_bricks = (RIGHT_WALL - LEFT_WALL) - 2. * GAP_BETWEEN_BRICKS_AND_SIDES; let total_width_of_bricks = (RIGHT_WALL - LEFT_WALL) - 2. * GAP_BETWEEN_BRICKS_AND_SIDES;