Loading font

Before going any further, we actually need a font. I chose Lucida console, but pick the one you prefer, it doesn't really matter. Once downloaded, put it in the assets folder as well. Now, time to actually load the font:

     let font = ttf_context.load_font("assets/lucida.ttf", 128).expect("
Couldn't load the font"
);

Note that if you want to apply a style to your font (such as bold, italic, strikethrough, or underline), that's the object on which you need to apply it. Here is an example:

    font.set_style(sdl2::ttf::STYLE_BOLD);

Now, two steps are remaining to be able to actually display text:

  1. Render the text.
  2. Create a texture from it.

Let's write a function in order to do so:

    fn create_texture_from_text<'a>(texture_creator: &'a 
TextureCreator<WindowContext>, font: &sdl2::ttf::Font, text: &str, r: u8, g: u8, b: u8, ) -> Option<Texture<'a>> { if let Ok(surface) = font.render(text) .blended(Color::RGB(r, g, b)) { texture_creator.create_texture_from_surface(&surface).ok() } else { None } }

Looks a lot like create_texture_rect, right?

Why not test it? Let's call the function and paste the texture onto the screen to see:

     let rendered_text = create_texture_from_text(&texture_creator,
&font, "test", 255, 255, 255).expect("Cannot render text"); canvas.copy(&rendered_text, None, Some(Rect::new(width as i32 -
40, 0, 40, 30))) .expect("Couldn't copy text");

And it looks like this:

Figure 4.3

For the texture rectangle, I use the following rule: one character is a block of 10 x 30 pixels. So in this example, since test has 4 letters, we need a block of 40 x 30 pixels. Let's write a function to make this easier:

     fn get_rect_from_text(text: &str, x: i32, y: i32) -> Option<Rect> {
        Some(Rect::new(x, y, text.len() as u32 * 20, 30))
     }

Ok, so now is the time to render the game information and write a new function to do it:

    fn display_game_information<'a>(tetris: &Tetris,
       canvas: &mut Canvas<Window>,
       texture_creator: &'a TextureCreator<WindowContext>,
       font: &sdl2::ttf::Font,
       start_x_point: i32) {
     let score_text = format!("Score: {}", tetris.score);
     let lines_sent_text = format!("Lines sent: {}", tetris.nb_lines);
     let level_text = format!("Level: {}", tetris.current_level);

     let score = create_texture_from_text(&texture_creator, &font,
        &score_text, 255, 255, 255)
        .expect("Cannot render text");
     let lines_sent = create_texture_from_text(&texture_creator, &font,
        &lines_sent_text, 255, 255, 255)
        .expect("Cannot render text");
     let level = create_texture_from_text(&texture_creator, &font,
        &level_text, 255, 255, 255)
        .expect("Cannot render text");
     
     canvas.copy(&score, None, get_rect_from_text(&score_text, 
start_x_point, 90)) .expect("Couldn't copy text"); canvas.copy(&lines_sent, None, get_rect_from_text(&score_text,
start_x_point, 125)) .expect("Couldn't copy text"); canvas.copy(&level, None, get_rect_from_text(&score_text,
start_x_point, 160)) .expect("Couldn't copy text"); }

And then we call it, as follows:

    display_game_information(&tetris, &mut canvas, &texture_creator, &font,
       width as i32 - grid_x - 10);

And now it looks like this:

Figure 4.4

Wonderful, we have the game information in real time! Isn't it awesome? What? It's ugly and overlaps the game? Let's move the game then! Instead of centering it, we'll give it a fixed x position (which will make our formula way simpler).

First, let's update our grid_x variable:

    let grid_x = 20;

Then, let's update so canvas.copy calls:

     canvas.copy(&border,
            None,
            Rect::new(10,
                      (height - TETRIS_HEIGHT as u32 * 16) as i32 / 2 - 10,
                      TETRIS_HEIGHT as u32 * 10 + 20, TETRIS_HEIGHT as u32 * 16 + 20))
      .expect("Couldn't copy texture into window");
     canvas.copy(&grid,
       None,
       Rect::new(20,
       (height - TETRIS_HEIGHT as u32 * 16) as i32 / 2,
        TETRIS_HEIGHT as u32 * 10, TETRIS_HEIGHT as u32 * 16))
      .expect("Couldn't copy texture into window");

And that's it. You now have a nice Tetris playing:

Figure 4.5

We could improve the display a bit by adding a border around the text, or even display a preview of the next piece, or even add a ghost, but I think that, from this point, you can add them easily.

That's it for this Tetris, have fun while playing with the sdl2!