Prerequisites

Before we start, ensure you have the following:

  • Rust installed on your machine. You can install it from rust-lang.org.
  • The latest version of Cargo, Rust's package manager, which comes with the Rust installation.
  • Basic understanding of Rust syntax and concepts.

Setting Up Your Project

First, create a new Rust project using Cargo:

cargo new bevy_game
cd bevy_game

Next, we need to add Bevy as a dependency. Open the Cargo.toml file and add the following line under [dependencies]:

[dependencies]
bevy = "0.5"

Now, run the following command to fetch the dependencies:

cargo build

Creating the Game Structure

In the src directory, open the main.rs file and replace its content with the following code:

use bevy::prelude::*;

struct Player;

fn main() {
    App::build()
        .insert_resource(WindowDescriptor {
            title: "Simple Bevy Game".to_string(),
            width: 800.0,
            height: 600.0,
            ..Default::default()
        })
        .add_startup_system(setup.system())
        .add_system(movement_system.system())
        .add_plugins(DefaultPlugins)
        .run();
}

fn setup(mut commands: Commands, mut materials: ResMut<Assets<ColorMaterial>>) {
    commands.spawn_bundle(OrthographicCameraBundle::new_2d());

    commands.spawn_bundle(SpriteBundle {
        material: materials.add(Color::rgb(0.2, 0.7, 0.2).into()),
        sprite: Sprite::new(Vec2::new(50.0, 50.0)),
        ..Default::default()
    })
    .insert(Player);
}

fn movement_system(
    keyboard_input: Res<Input<KeyCode>>,
    mut query: Query<(&Player, &mut Transform)>,
) {
    for (_, mut transform) in query.iter_mut() {
        let mut direction = Vec3::ZERO;

        if keyboard_input.pressed(KeyCode::W) {
            direction.y += 1.0;
        }
        if keyboard_input.pressed(KeyCode::S) {
            direction.y -= 1.0;
        }
        if keyboard_input.pressed(KeyCode::A) {
            direction.x -= 1.0;
        }
        if keyboard_input.pressed(KeyCode::D) {
            direction.x += 1.0;
        }

        transform.translation += direction.normalize_or_zero() * 5.0; // Speed
    }
}

Explanation of the Code

  • App Initialization: The App::build() function initializes the Bevy application. We set up the window and add necessary systems and plugins.
  • Setup Function: The setup function creates the camera and the player entity. The player is represented by a green square sprite.
  • Movement System: The movement_system function checks for keyboard input and moves the player entity accordingly. The player can move up, down, left, and right using the W, A, S, and D keys.

Running the Game

To run your game, execute the following command in your terminal:

cargo run

You should see a window open with a green square that you can move around using the keyboard.

Enhancing the Game

While the above code gives you a basic structure, you can enhance your game in several ways:

Adding Boundaries

You can restrict the player’s movement within the window boundaries. Update the movement_system function as follows:

fn movement_system(
    keyboard_input: Res<Input<KeyCode>>,
    mut query: Query<(&Player, &mut Transform)>,
) {
    for (_, mut transform) in query.iter_mut() {
        let mut direction = Vec3::ZERO;

        if keyboard_input.pressed(KeyCode::W) {
            direction.y += 1.0;
        }
        if keyboard_input.pressed(KeyCode::S) {
            direction.y -= 1.0;
        }
        if keyboard_input.pressed(KeyCode::A) {
            direction.x -= 1.0;
        }
        if keyboard_input.pressed(KeyCode::D) {
            direction.x += 1.0;
        }

        let speed = 5.0;
        let new_translation = transform.translation + direction.normalize_or_zero() * speed;

        // Restrict movement within window boundaries
        transform.translation.x = new_translation.x.clamp(-400.0, 400.0);
        transform.translation.y = new_translation.y.clamp(-300.0, 300.0);
    }
}

Adding More Entities

You can spawn more entities or create different shapes. For instance, to add a red square, you can modify the setup function:

commands.spawn_bundle(SpriteBundle {
    material: materials.add(Color::rgb(1.0, 0.0, 0.0).into()),
    sprite: Sprite::new(Vec2::new(50.0, 50.0)),
    transform: Transform::from_translation(Vec3::new(100.0, 100.0, 0.0)),
    ..Default::default()
});

Conclusion

In this tutorial, we created a simple 2D game using the Bevy game engine in Rust. You learned how to set up a project, handle player input, and implement basic movement mechanics. From here, you can expand your game by adding features such as scoring, levels, or additional game mechanics.

Learn more with useful resources: