Making Games in Rust - Part 1 - Bevy and ECS
Tags: rust, bevy, rapier, tutorial
Published: 2021-12-07 23:44:43

## Context

I recently stumbled upon a short [YouTube video](https://www.youtube.com/watch?v=Q0-xjeEiYw4) of somebody building a roguelike game in Rust.
From there, jumping from resource to resource, I ended up going through (part) of [this massive (and awesome) tutorial](https://bfnightly.bracketproductions.com/chapter_1.html) by Herbert Wolverson about his Rust library [bracket_lib](https://github.com/amethyst/bracket-lib). In this tutorial, Wolverson builds a roguelike game with colored text characters.
After reading through, I felt like writing another type of game in Rust, so I looked at the available Rust game engines. The most popular, seems to be [Amethyst](https://amethyst.rs/), but it looks like they [halted their development efforts](https://amethyst.rs/posts/amethyst--starting-fresh). Second in line was [Bevy](https://bevyengine.org/). People are using it, support for Android and iOS is on the way, uses an ECS and have some usage examples: looks good.

Now we have a language: Rust, a game engine: Bevy, and a genre: Platformer.

This series of posts will be a journal of my journey building a small platformer game with these tools.

## ECS

Let's first go over the theory: what is an ECS?

An ECS, or Entity Component System is an architectural pattern used to structure games. There are 3 components to this pattern:

- Entities: An entity identifies a game object, such as a player, a monster, a wall, etc. Technically, it acts as an identifier that points to multiple components.
- Components: A component is the data/properties for an aspect of the game. Examples of this would be a position, a monster AI or a map. A entity is the composition of multiple components.
- Systems: systems contain the logic of our game. They perform actions on the entities that possess the components matching a given query.

## Bevy's ECS

Let's start by creating a new rust project:

```sh
cargo new platformer
```

- Open the newly created project in your favorite code editor - and navigate to the `cargo.toml` file.
- Add a dependency to bevy.

In the end, your `cargo.toml` file should look like this:

```toml
[package]
name = "platformer"
version = "0.1.0"
edition = "2021"

[dependencies]
bevy = "0.5"
```

- Navigate to the `main.rs file`
- Replace its content by:

```rs
use bevy::prelude::*;

fn main() {
    App::build().run();
}
```

`use bevy::prelude::*;` imports Bevy modules, and the `main` function starts Bevy. In the end, this code will launch Bevy and exit. It you run `cargo run`, nothing will happen. This is expected. We have just been through the second part of [Bevy's getting started guide](https://bevyengine.org/learn/book/getting-started/apps/).

Now let's see how ECS works in Bevy.

### Components

Components in Bevy are plain old Rusty struct. Ex:

```rs
struct Position { x: f32, y: f32 }
```

### Systems

Systems are plain old rusty functions:

```rs
fn print_position_system(query: Query<&Transform>) {
    for transform in query.iter() {
        println!("position: {:?}", transform.translation);
    }
}
```

Bevy automatically converts your Rust functions to its internal `System` type via a trait extension method. So to register a system with Bevy, one can do:

```rs
// Declaring the system
fn hello_world() {
    println!("hello world!");
}

fn main() {
    App::build()
        .add_system(hello_world.system()) // Registering the system
        .run();
}
```

### Entities

Bevy's getting started guide says that it represents entities as a simple type containing a unique integer:

```rs
struct Entity(u64);
```

But really, you won't really notice. To declare a new entity, one can call the `Commands.spawn()` method and insert multiple components as such:

```rs
fn add_people(mut commands: Commands) {
    commands.spawn().insert(Person).insert(Name("Elaina Proctor".to_string()));
    commands.spawn().insert(Person).insert(Name("Renzo Hume".to_string()));
    commands.spawn().insert(Person).insert(Name("Zayna Nieves".to_string()));
}
```

You may run this code with the following components, startup method and systems:

```rs
// Components
struct Person;

struct Name(String);

// main
fn main() {
    App::build()
        .add_startup_system(add_people.system())
        .add_system(greet_people.system())
        .run();
}

// Systems
fn add_people(mut commands: Commands) {
    commands.spawn().insert(Person).insert(Name("Elaina Proctor".to_string()));
    commands.spawn().insert(Person).insert(Name("Renzo Hume".to_string()));
    commands.spawn().insert(Person).insert(Name("Zayna Nieves".to_string()));
}

fn greet_people(query: Query<&Name, With<Person>>) {
    for name in query.iter() {
        println!("hello {}!", name.0);
    }
}
```

This should yield:

```
hello Elaina Proctor!
hello Renzo Hume!
hello Zayna Nieves!
```

in your terminal.

## Creating a Platformer - Step 1 - The Window

The following code will create a new 640x400 window with the title `Platformer!`.

```rs
fn main() {
    App::build()
        .insert_resource(WindowDescriptor {
            title: "Platformer!".to_string(),
            width: 640.0,
            height: 400.0,
            vsync: true,
            ..Default::default()
        })
        .add_plugins(DefaultPlugins)
        .run();
}
```

You may have notice the line: `.add_plugins(DefaultPlugins)`. This line adds Bevy's `Default` Plugins, which includes the base features expected from a game engine: 2D and 3D renderer, windows, user inputs handling, etc. This is explained in greater details on [step 4 of Bevy's getting started tutorial](https://bevyengine.org/learn/book/getting-started/plugins/).

Plugins are a useful part of Bevy that allow you to group together multiple resources, components, systems. More on that later.

It is also possible to modify the background color of the window:

```rs
.insert_resource(ClearColor(Color::rgb(0.04, 0.04, 0.04)))
```

Now run `cargo run`:

🤩🤩🤩


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

🤩🤩🤩

Code available [here](https://github.com/belzile/platformer/tree/v0.0.1).