Making Games in Rust - Part 6 - Generating a Map
Tags: rust, tutorial, bevy
Published: 2021-12-26 19:16:40

For future features, we will need a bigger world to move our player in. We need a bigger map.

This article builds on top of our previous code (the code I started with can be found [here](https://github.com/belzile/platformer/tree/part-6-pre)) and adds an automatically generated map to our world.

## Flat Floor

In `map.rs`, let's replace our `spawn_floor` method with the following code:

```rs
pub fn spawn_floor(mut commands: Commands, materials: Res<Materials>) {
    for x in 0..50 {
        add_tile(&mut commands, &materials, x as f32)
    }
}

fn add_tile(commands: &mut Commands, materials: &Res<Materials>, x: f32) {
    let rigid_body = RigidBodyBundle {
        position: Vec2::new(x, -2.).into(),
        body_type: RigidBodyType::Static,
        ..Default::default()
    };
    let collider = ColliderBundle {
        shape: ColliderShape::cuboid(0.5, 0.5),
        ..Default::default()
    };
    commands
        .spawn_bundle(SpriteBundle {
            material: materials.floor_material.clone(),
            sprite: Sprite::new(Vec2::new(1., 1.)),
            ..Default::default()
        })
        .insert_bundle(rigid_body)
        .insert_bundle(collider)
        .insert(RigidBodyPositionSync::Discrete);
}
```

Compared to our previous code, we:

1. Moved the content of the `spawn_floor` function to an `add_tile` function.
2. Modify the input of the `add_tile` function so that it receives an `x` coordinate as well.
3. Modify the width of our tiles from 10 to 1 world unit.
4. Set the x component of our rigid body to the `x` coordinate provided as input.

The new `spawn_floor` function now contains a loop which calls our `add_tile` function with a coordinate going from 0 to 50.

Running the game will display a flat floor of length 50.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/37liscsxg61s6jgrsdkf.png)

(Ha! Yeah! our player is also pink now)

## Going Up or Down

To make this more interesting, our map should go up or down. Let's modify our `add_tile` function so that it takes a height as input:

```rs
fn add_tile(commands: &mut Commands, materials: &Res<Materials>, x: f32, height: u8) {
    let half_height = height as f32 / 2.;
    let rigid_body = RigidBodyBundle {
        position: Vec2::new(x, -2. + half_height).into(),
        body_type: RigidBodyType::Static,
        ..Default::default()
    };
    let collider = ColliderBundle {
        shape: ColliderShape::cuboid(0.5, half_height),
        ..Default::default()
    };
    commands
        .spawn_bundle(SpriteBundle {
            material: materials.floor_material.clone(),
            sprite: Sprite::new(Vec2::new(1., height as f32)),
            ..Default::default()
        })
        .insert_bundle(rigid_body)
        .insert_bundle(collider)
        .insert(RigidBodyPositionSync::Discrete);
}
```

We will randomly determine the height to provide:

1. Add the `rand` crate to your `cargo.toml`:

```toml
[dependencies]
rand = "0.8.4"
```

2. Add a function to randomly pick an height variation:

```rs
use rand::prelude::*;
// ...
fn get_random_height_delta() -> i8 {
    let mut rng = thread_rng();
    let random_number: u32 = rng.gen_range(0..100);
    let delta = match random_number {
        0..=70 => 0,
        71..=80 => -1,
        81..=90 => 1,
        _ => 2,
    };
    delta
}
```

3. Add a function to calculate the next height from the current height:

```rs
fn get_next_height(current_height: u8) -> u8 {
    let next_height = current_height as i8 + get_random_height_delta();
    return if next_height > 0 {
        next_height as u8
    } else {
        1
    };
}
```

4. Finally, modify the `spawn_floor` function to send a random height to the `add_tile` function:

```rs
pub fn spawn_floor(mut commands: Commands, materials: Res<Materials>) {
    let mut height = 1;
    for x in 0..150 {
        add_tile(&mut commands, &materials, x as f32, height);
        height = get_next_height(height)
    }
}
```

Running the game should render a prettier map:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6uohp3zjfjdil2uf2vgm.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a49zztjvdcrbmqkyvi0r.png)

The final code is available [here](https://github.com/belzile/platformer/tree/part-6).