Adding Paddle Configs

We're finally going to add a configuration struct for our Paddles. Because our Pong clone supports two players, we should let them configure each separately. Add the following to the config.rs file:

#[derive(Debug, Deserialize, Serialize)]
pub struct PaddleConfig {
    pub height: f32,
    pub width: f32,
    pub velocity: f32,
    pub color: (f32, f32, f32, f32),
}

impl Default for PaddleConfig {
    fn default() -> Self {
        PaddleConfig {
            height: 15.0,
            width: 2.5,
            velocity: 75.0,
            color: (0.0, 0.0, 1.0, 1.0),
        }
    }
}

Just like the BallConfig, we need to read in the color as a tuple instead of an array.

Now, to allow us to have two separate PaddleConfigs, we will wrap them in a bigger structure as follows:

#[derive(Debug, Default, Deserialize, Serialize)]
pub struct PaddlesConfig {
    pub left: PaddleConfig,
    pub right: PaddleConfig,
}

Now we need to add the PaddlesConfig to our PongConfig as shown below

pub struct PongConfig {
    pub arena: ArenaConfig,
    pub ball: BallConfig,
    pub paddles: PaddlesConfig,
}

and modify the main.rs's run() function to add our PaddleConfigs.

    .with_resource(pong_config.arena)
    .with_resource(pong_config.ball)
    .with_resource(pong_config.paddles)
    .with_bundle(PongBundle::default())?

We add the PaddlesConfig to the World, rather than as separate left and right configurations because Systems can only access resources with ID 0. Any resource added using World::add_resource is added using a default ID of 0. You must use World::add_resource_with_id to add multiple resources of the same type, but then the Systems cannot properly differentiate between them.

Replacing Constants with Configs

Replacing all instances of PADDLE_* will be similar to the BallConfig, as we only use those values for creating the paddle entities. However, we will need to separate the PaddlesConfig into left and right. To avoid issues with the borrow checker, we read the PaddlesConfig once and copy all of the values, unwrapping them in one big assignment statement. In initialise_paddles() in pong.rs, add this code below reading the ArenaConfig.

let (
    left_height,
    left_width,
    left_velocity,
    left_color,
    right_height,
    right_width,
    right_velocity,
    right_color,
) = {
    let config = &world.read_resource::<PaddlesConfig>();
    let cl: [f32; 4] = [
        config.left.color.0,
        config.left.color.1,
        config.left.color.2,
        config.left.color.3,
    ];
    let cr: [f32; 4] = [
        config.right.color.0,
        config.right.color.1,
        config.right.color.2,
        config.right.color.3,
    ];
    (
        config.left.height,
        config.left.width,
        config.left.velocity,
        cl,
        config.right.height,
        config.right.width,
        config.right.velocity,
        cr,
    )
};

Now, within this function, replace

let y = (arena_height - PADDLE_HEIGHT) / 2.0;

with

let left_y = (arena_height - left_height) / 2.0;
let right_y = (arena_height - right_height) / 2.0;

You will also need to repeat the calls to create_mesh and create_color_material() so that you have a left and right mesh and left and right color.

Now, use the left- and right-specific values in the world.create_entity() calls.

Modifying config.ron

Now for the final modification of our config.ron file. For fun, let's make the right paddle yellow and keep the left paddle blue so the final config.ron file will be as follows:

(
    arena: (
        height: 100.0,
        width: 100.0,
    ),
    ball: (
        velocity: Vector2(
            x: 75.0,
            y: 50.0,
        ),
        radius: 2.5,
        color: (1.0, 0.647, 0.0, 1.0),
    ),
    paddles: (
        left: (
            height: 15.0,
            width: 2.5,
            velocity: 75.0,
            color: (0.0, 0.0, 1.0, 1.0),
        ),
        right: (
            height: 15.0,
            width: 2.5,
            velocity: 75.0,
            color: (0.0, 1.0, 1.0, 1.0),
        ),
    )
)