Adding an Arena Config

To begin with, let's make the Arena dimensions configurable. Add this structure to a new file config.rs.

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

impl Default for ArenaConfig {
    fn default() -> Self {
        ArenaConfig {
            height: 100.0,
            width: 100.0,
        }
    }
}

The default values match the values used in the full example, so if we don't use a config file things will look just like the Pong example. Another option would be to use [#serde(default)], which allows you to set the default value of a field if that field is not present in the config file. This is different than the Default trait in that you can set default values for some fields while requiring others be present. For now though, let's just use the Default trait.

Adding the Config to the World

Now, in main.rs, add the following lines:

use crate::config::ArenaConfig;

We'll need to load the config at startup, so let's add this to the run function in main.rs

let arena_config = ArenaConfig::load(&config)?;

Now that we have loaded our config, we want to add it to the world so other modules can access it. We do this by adding the config as a resource during Application creation:

    .with_resource(arena_config)
    .with_bundle(PongBundle::default())?

Now for the difficult part: replacing every use of ARENA_WIDTH and ARENA_HEIGHT with our config object. First, let's change our initialisation steps in pong.rs.

Add the following line to the top of pong.rs:

use crate::config::ArenaConfig;

Now, in the initialise_paddles() function, add the following lines after the initialisation of the left_transform and right_transform.

let (arena_height, arena_width) = {
    let config = &world.read_resource::<ArenaConfig>();
    (config.height, config.width)
};

Now replace all references to ARENA_HEIGHT with arena_height and all references to ARENA_WIDTH with arena_width. Do this for each initialisation function in pong.rs.

Accessing Config Files from Systems

It is actually simpler to access a Config file from a system than via the World directly. To access it in the System's run() function, add it to the SystemData type. This is what the BounceSystem looks like when it wants to access the ArenaConfig.

use crate::config::ArenaConfig;
...
type SystemData = (
    WriteStorage<'s, Ball>,
    ReadStorage<'s, Paddle>,
    ReadStorage<'s, Transform>,
    Read<'s, AssetStorage<Source>>,
    ReadExpect<'s, Sounds>,
    Read<'s, Option<Output>>,
    Read<'s, ArenaConfig>,
);
...
fn run(&mut self,
       (mut balls, paddles, transforms, storage, sounds, audio_output, arena_config): SystemData) {

Now, in the run() function, replace the reference to ARENA_HEIGHT with arena_config.height.

Add Read<'s, ArenaConfig> to the WinnerSystem and PaddleSystem as well, replacing the reference to ARENA_WIDTH with arena_config.width.

Making config.ron

Now for the final part: actually creating our config.ron file. This will be very simple right now, and expand as we add more configurable items. For now, just copy and paste the following into a new file. Feel free to modify the height and width if you want.

arena: (
    height: 100.0,
    width: 100.0,
)