Making Games in Rust - Part 6 - Generating a Map

sbelzile

Sébastien Belzile

Posted on December 26, 2021

Making Games in Rust - Part 6 - Generating a Map

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) 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:



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);
}


Enter fullscreen mode Exit fullscreen mode

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

(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:



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);
}


Enter fullscreen mode Exit fullscreen mode

We will randomly determine the height to provide:

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


[dependencies]
rand = "0.8.4"


Enter fullscreen mode Exit fullscreen mode
  1. Add a function to randomly pick an height variation:


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
}


Enter fullscreen mode Exit fullscreen mode
  1. Add a function to calculate the next height from the current height:


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
    };
}


Enter fullscreen mode Exit fullscreen mode
  1. Finally, modify the spawn_floor function to send a random height to the add_tile function:


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)
    }
}


Enter fullscreen mode Exit fullscreen mode

Running the game should render a prettier map:

Image description

Image description

The final code is available here.

💖 💪 🙅 🚩
sbelzile
Sébastien Belzile

Posted on December 26, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related