Jelajahi Sumber

Finished Rendering UI

runningwater 1 tahun lalu
induk
melakukan
8202e0ff6e
4 mengubah file dengan 247 tambahan dan 56 penghapusan
  1. 1 0
      .gitignore
  2. 1 0
      Cargo.toml
  3. TEMPAT SAMPAH
      assets/LucidaGrande.ttf
  4. 245 56
      src/main.rs

+ 1 - 0
.gitignore

@@ -1 +1,2 @@
 /target
+scores.txt

+ 1 - 0
Cargo.toml

@@ -9,4 +9,5 @@ edition = "2021"
 sdl2 = "0.36.0"
 rand = "0.8.5"
 [features]
+default = ["sdl2/ttf"]
 #default = ["sdl2/image"]

TEMPAT SAMPAH
assets/LucidaGrande.ttf


+ 245 - 56
src/main.rs

@@ -10,15 +10,17 @@ use std::time::{Duration, SystemTime};
 use sdl2::event::Event;
 use sdl2::keyboard::Keycode;
 use sdl2::pixels::Color;
+use sdl2::rect::Rect;
 use sdl2::render::{Texture, TextureCreator, WindowCanvas};
 use sdl2::video::WindowContext;
 
-// Crate a texture with 32x32 size
-const TEXTURE_SIZE: u32 = 32;
 const SCORE_FILE_NAME: &str = "scores.txt";
 const LEVEL_TIMES: [u32; 10] = [1000, 850, 700, 600, 500, 400, 300, 250, 221, 190];
-const LEVEL_LINES: [u32; 10] = [20, 40, 60, 80, 100, 120, 140, 160, 180, 200]; // 需要消除多少行才能升级
+const LEVEL_LINES: [u32; 10] = [10, 40, 60, 80, 100, 120, 140, 160, 180, 200]; // 需要消除多少行才能升级
 const NB_HIGHSCORES: usize = 5;
+const TETRIS_HEIGHT: usize = 42;
+const TETRIS_HEIGHT_MINI: usize = 26;
+
 type Piece = Vec<Vec<u8>>;
 type States = Vec<Piece>;
 
@@ -27,6 +29,7 @@ struct Tetrimino {
     x: isize,
     y: usize,
     current_state: u8,
+    index: i8,
 }
 
 impl Tetrimino {
@@ -35,7 +38,6 @@ impl Tetrimino {
         if tmp_state as usize >= self.states.len() {
             tmp_state = 0;
         }
-
         let x_pos = [0, -1, 1, -2, 2, -3];
         for x in x_pos.iter() {
             if self.test_position(game_map, tmp_state as usize, self.x + x, self.y) == true {
@@ -100,6 +102,7 @@ impl TetriminoGenerator for TetriminoI {
             x: 4,
             y: 0,
             current_state: 0,
+            index: -1,
         }
     }
 }
@@ -137,6 +140,7 @@ impl TetriminoGenerator for TetriminoJ {
             x: 4,
             y: 0,
             current_state: 0,
+            index: -1,
         }
     }
 }
@@ -174,6 +178,7 @@ impl TetriminoGenerator for TetriminoL {
             x: 4,
             y: 0,
             current_state: 0,
+            index: -1,
         }
     }
 }
@@ -191,6 +196,7 @@ impl TetriminoGenerator for TetriminoO {
             x: 5,
             y: 0,
             current_state: 0,
+            index: -1,
         }
     }
 }
@@ -216,6 +222,7 @@ impl TetriminoGenerator for TetriminoS {
             x: 4,
             y: 0,
             current_state: 0,
+            index: -1,
         }
     }
 }
@@ -241,6 +248,7 @@ impl TetriminoGenerator for TetriminoZ {
             x: 4,
             y: 0,
             current_state: 0,
+            index: -1,
         }
     }
 }
@@ -278,6 +286,7 @@ impl TetriminoGenerator for TetriminoT {
             x: 4,
             y: 0,
             current_state: 0,
+            index: -1,
         }
     }
 }
@@ -402,26 +411,20 @@ impl Tetris {
         }
     }
 }
-
-#[derive(Clone, Copy)]
-enum TextureColor {
-    Green,
-    Blue,
-}
-
 fn create_texture_rect<'a>(
     canvas: &mut WindowCanvas,
     texture_creator: &'a TextureCreator<WindowContext>,
-    color: TextureColor,
-    size: u32,
+    r: u8,
+    g: u8,
+    b: u8,
+    width: u32,
+    height: u32,
 ) -> Option<Texture<'a>> {
-    if let Ok(mut square_texture) = texture_creator.create_texture_target(None, size, size) {
+    if let Ok(mut square_texture) = texture_creator.create_texture_target(None, width, height) {
         canvas
             .with_texture_canvas(&mut square_texture, |texture| {
-                match color {
-                    TextureColor::Green => texture.set_draw_color(Color::RGB(0, 255, 0)),
-                    TextureColor::Blue => texture.set_draw_color(Color::RGB(0, 0, 255)),
-                }
+                // texture.set_draw_color(Color::RGBA(r, g, b,rand::random::<u8>() % 254 + 1));
+                texture.set_draw_color(Color::RGBA(r, g, b,2));
                 texture.clear();
             })
             .expect("Failed to color a texture");
@@ -431,6 +434,90 @@ fn create_texture_rect<'a>(
     }
 }
 
+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
+    }
+}
+
+fn get_rect_from_text(text: &str, x: i32, y: i32) -> Option<Rect> {
+    Some(Rect::new(x, y, text.len() as u32 * 10, 20))
+}
+
+fn display_game_information<'a>(
+    tetris: &Tetris,
+    mut canvas: &mut WindowCanvas,
+    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 border_preview = create_texture_rect(
+        &mut canvas,
+        &texture_creator,
+        255,
+        255,
+        255,
+        TETRIS_HEIGHT as u32 * 4 + 20,
+        TETRIS_HEIGHT as u32 * 10 + 20,
+    )
+    .expect("Failed to create a texture");
+
+    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(&lines_sent_text, start_x_point, 125),
+        )
+        .expect("Couldn't copy text");
+    canvas
+        .copy(
+            &level,
+            None,
+            get_rect_from_text(&level_text, start_x_point, 160),
+        )
+        .expect("Couldn't copy text");
+
+    canvas
+        .copy(
+            &border_preview,
+            None,
+            Rect::new(
+                start_x_point,
+                195,
+                TETRIS_HEIGHT_MINI as u32 * 4 + 20,
+                TETRIS_HEIGHT_MINI as u32 * 10 + 20,
+            ),
+        )
+        .expect("Couldn't copy canvas");
+}
+
 /// # 写入文件
 /// @content 内容
 ///
@@ -499,52 +586,86 @@ fn load_highscores_and_lines() -> Option<(Vec<u32>, Vec<u32>)> {
 pub fn main() {
     let sdl_context = sdl2::init().expect("SDL init failed");
     let video_subsystem = sdl_context.video().expect("Couldn't get video subsystem");
+    let ttf_content = sdl2::ttf::init().expect("SDL TTF init failed");
+    let font = ttf_content
+        .load_font("assets/LucidaGrande.ttf", 30)
+        .expect("couldn't load the font");
+    //    font.set_style(FontStyle::BOLD);
+    let width = 600;
+    let height = 750;
+    let mut timer = SystemTime::now();
+    let mut tetris = Tetris::new();
+
+    let mut event_pump = sdl_context
+        .event_pump()
+        .expect("Failed to get SDL event pump");
+
+    let grid_x = 20;
+    let grid_y = (height - TETRIS_HEIGHT as u32 * 16) as i32 / 2;
 
-    // Parameters are: title, width, height
     let window = video_subsystem
-        .window("rust-sdl2 demo", 800, 600)
-        .position_centered() // to put it in the middle of the screen
+        .window("Tetris", width, height)
+        .position_centered() // top put it in the middle of the screen
         .build() // to create the window
-        .unwrap();
+        .expect("Failed to create window");
 
     let mut canvas = window
         .into_canvas()
         .target_texture()
         .present_vsync() // To enable v-sync.
         .build()
-        .expect("Failed to get SDL event pump");
-
-    let texture_creator: TextureCreator<_> = canvas.texture_creator();
+        .expect("Couldn't get window's canvas");
 
-    // Web create a texture with a 32x32 size.
-    let green_square = create_texture_rect(
+    let texture_creator = canvas.texture_creator();
+    let grid = create_texture_rect(
         &mut canvas,
         &texture_creator,
-        TextureColor::Green,
-        TEXTURE_SIZE,
+        0,
+        0,
+        0,
+        TETRIS_HEIGHT as u32 * 10,
+        TETRIS_HEIGHT as u32 * 16,
     )
     .expect("Failed to create a texture");
-
-    let blue_square = create_texture_rect(
+    let border = create_texture_rect(
         &mut canvas,
         &texture_creator,
-        TextureColor::Blue,
-        TEXTURE_SIZE,
+        255,
+        255,
+        255,
+        TETRIS_HEIGHT as u32 * 10 + 20,
+        TETRIS_HEIGHT as u32 * 16 + 20,
     )
     .expect("Failed to create a texture");
 
-    let mut event_pump = sdl_context
-        .event_pump()
-        .expect("Failed to get SDL event pump");
+    macro_rules! texture {
+        ($r:expr, $g:expr, $b:expr) => {
+            create_texture_rect(
+                &mut canvas,
+                &texture_creator,
+                $b,
+                $g,
+                $b,
+                TETRIS_HEIGHT as u32,
+                TETRIS_HEIGHT as u32,
+            )
+            .unwrap()
+        };
+    }
 
-    let mut timer = SystemTime::now();
-    let mut tetris = Tetris::new();
+    let textures = [
+        texture!(255, 69, 69),
+        texture!(255, 220, 69),
+        texture!(237, 150, 37),
+        texture!(171, 99, 237),
+        texture!(77, 149, 239),
+        texture!(39, 218, 225),
+        texture!(45, 216, 47),
+        texture!(255, 255, 255),
+    ];
 
     loop {
-        if match timer.elapsed() {
-            Ok(elapsed) => elapsed.as_secs() >= 1,
-            Err(_) => false,
-        } {
+        if is_time_over(&tetris, &timer) {
             let mut make_permanent = false;
             if let Some(ref mut piece) = tetris.current_piece {
                 let x = piece.x;
@@ -554,12 +675,39 @@ pub fn main() {
             if make_permanent {
                 tetris.make_permanent();
             }
-
             timer = SystemTime::now();
         }
 
-        // We need to draw the tetris "grid" in here.
+        // We need to draw the game map in here.
+        canvas.set_draw_color(Color::RGB(255, 0, 0));
+        canvas.clear();
 
+        // We need to draw the tetris "grid" in here.
+        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");
+        
         if tetris.current_piece.is_none() {
             let current_piece = tetris.create_new_tetrimino();
             if !current_piece.test_current_position(&tetris.game_map) {
@@ -568,32 +716,73 @@ pub fn main() {
             }
             tetris.current_piece = Some(current_piece);
         }
+
         let mut quit = false;
         if !handle_events(&mut tetris, &mut quit, &mut timer, &mut event_pump) {
             if let Some(ref mut piece) = tetris.current_piece {
                 // We need to draw our current tetrimino in here.
-                todo!()
+                for (line_bn, line) in piece.states[piece.current_state as usize]
+                    .iter()
+                    .enumerate()
+                {
+                    for (case_nb, case) in line.iter().enumerate() {
+                        if *case == 0 {
+                            continue;
+                        }
+                        // The new part is here
+                        canvas
+                            .copy(
+                                &textures[*case as usize - 1],
+                                None,
+                                Rect::new(
+                                    grid_x
+                                        + (piece.x + case_nb as isize) as i32
+                                            * TETRIS_HEIGHT as i32,
+                                    grid_y + (piece.y + line_bn) as i32 * TETRIS_HEIGHT as i32,
+                                    TETRIS_HEIGHT as u32,
+                                    TETRIS_HEIGHT as u32,
+                                ),
+                            )
+                            .expect("Couldn't copy texture into window");
+                    }
+                }
             }
         }
+
         if quit {
             print_game_information(&tetris);
             break;
         }
 
-        if is_time_over(&tetris, &timer) {
-            let mut make_permanent = false;
-            if let Some(ref mut piece) = tetris.current_piece {
-                let x = piece.x;
-                let y = piece.y + 1;
-                make_permanent = !piece.change_position(&tetris.game_map, x, y);
-            }
-            if make_permanent {
-                tetris.make_permanent();
+        for (line_nb, line) in tetris.game_map.iter().enumerate() {
+            for (case_nb, case) in line.iter().enumerate() {
+                if *case == 0 {
+                    continue;
+                }
+                canvas
+                    .copy(
+                        &textures[7],
+                        None,
+                        Rect::new(
+                            grid_x + case_nb as i32 * TETRIS_HEIGHT as i32,
+                            grid_y + line_nb as i32 * TETRIS_HEIGHT as i32,
+                            TETRIS_HEIGHT as u32,
+                            TETRIS_HEIGHT as u32,
+                        ),
+                    )
+                    .expect("Couldn't copy texture into window");
             }
-            timer = SystemTime::now();
         }
-        // We need to draw the game map in here.
 
+        display_game_information(
+            &tetris,
+            &mut canvas,
+            &texture_creator,
+            &font,
+            width as i32 - grid_x - 120,
+        );
+
+        canvas.present();
         sleep(Duration::new(0, 1_000_000_000u32 / 60));
     }
 }