Creating a Tetris Clone in Rust, with Bevy (Part 1)

-Hello, Tetris

Posted by corbamico on November 12, 2020

Create Tetris Clone by Rust,Bevy (1)

Inspired by bevy-snake, cloning a tetris game by using bevy will be fun.
You may find final source here, and final game as:
tetris

Step 1.Show Windows/Background

let’s load png file, show background picture in game windows.
You may clone bevy-tetris and cargo run –example step1
Code Comments:

  • in bevy v0.3 default assets files are always in directory ‘./assets/’
  • initial windows size by add_resource(WindowDescriptor)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//we compile as windows app instead of console app
#![windows_subsystem = "windows"]
use bevy::prelude::*;
fn main(){
    App::build()
    //we initial windows size here:
    .add_resource(WindowDescriptor {
     title: "Tetris".to_string(),width: 360,height: 443,..Default::default()})
    .add_startup_system(setup.system())
    .add_plugins(DefaultPlugins)
    .run();
}
fn setup(mut commands: Commands,
    asset_server: Res<AssetServer>,
    mut materials: ResMut<Assets<ColorMaterial>>) {
    let start_handle = asset_server.load("screen.png");
    commands.spawn(Camera2dComponents::default())
        .spawn(SpriteComponents {
            material: materials.add(start_handle.into()),
            ..Default::default()
        });
}

Step 2.Draw a Dot

We acturely draw 3 square for one dot, code here:

  • a square(20x20) with black color
  • a square(16x16) with background color
  • a square(12x12) with black color
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
fn spwan_child_dot(
 commands: &mut ChildBuilder,
 black: Handle<ColorMaterial>,
 background: Handle<ColorMaterial>) {
    commands
        .spawn(NodeComponents {
            material: black.clone(),
            style: Style {
                size: Size::new(Val::Px(20.0), Val::Px(20.0)),.....
        })
        .with_children(|parent| {
            parent
                .spawn(NodeComponents {
                    material: background,
                    style: Style {
                        size: Size::new(Val::Px(16.0), Val::Px(16.0)),......
                })
                .with_children(|parent| {
                    parent.spawn(NodeComponents {
                        material: black,
                        style: Style {
                            size: Size::new(Val::Px(12.0), Val::Px(12.0)),.....
                    });
                });
        });
}

you will get one Dot in left/bottom of screen tetris

Step 3.Draw a tetromino/brick

We take the reference for tetromino drawing from tetromino tetromino

We create struct Dot(i8,i8), struct Brick{dots: [Dot; 4]} for presenting each tetromnio.
In this step3, we will draw a I tetromino, which draw 4 Dots with cordinate conversion dot_to_brick_x,dot_to_brick_y, code here:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
pub struct Dot(pub i8, pub i8);
pub struct Brick {pub dots: [Dot; 4]}
//eg. Tetromino I
Brick{dots:[Dot(0, 1), Dot(1, 1), Dot(2, 1), Dot(3, 1)]}

fn spwan_brick_at(
    commands: &mut Commands,
    black: Handle<ColorMaterial>,
    background: Handle<ColorMaterial>,
    brick: Brick,x: f32,y: f32) {
    commands
        .spawn(NodeComponents {
            style: Style {
                position_type: PositionType::Absolute,
                position: Rect {
                    left: Val::Px(x),
                    bottom: Val::Px(y),
                    ..Default::default()
                },
                ..Default::default()
            },
            ..Default::default()
        })
        .with_children(|child| {
            (0..4).for_each(|i| {
                spwan_child_dot(child, black.clone(), background.clone(), &brick.dots[i])
            });
        });
}

you will get one Dot in left/bottom of screen tetris