From 63b2ed39a56ffe6ea7a9d4fc3942cb3dce9f668a Mon Sep 17 00:00:00 2001 From: curly Date: Thu, 18 Aug 2022 13:57:29 -0600 Subject: much better --- TODO | 9 ----- src/lib.rs | 52 +++++++++++++++++++++++--- src/tetris.rs | 5 ++- src/tetris/piece.rs | 105 ++++++++++++++++++++++------------------------------ 4 files changed, 96 insertions(+), 75 deletions(-) diff --git a/TODO b/TODO index 7f15ac2..dc11de4 100644 --- a/TODO +++ b/TODO @@ -1,18 +1,9 @@ -Next piece in gui Add sounds (mostly for losing, winning and clearing a row) -Also add a pause Have a menu -Add to score on line clear redo input system. Feels good -Implement win condition and lose condition Colored blocks Grey blocks when dead -Gets faster the more lines you clear -Multiline bonus -If the piece placed has bits above the top, end game Fix aspect ratio to 1:1 Import pieces from files to make it data driven -Refactor getting 2d array from piece area - Make it a pointer to the values in the area \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 2508f18..f4679c4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,9 +11,11 @@ use sfml::system::{Vector2f, Vector2u}; pub struct Game { tickrate: Duration, // How many times things are checked a second + low_tickrate: Duration, // What's the lowest speed the game can run at maxfps: u64, window_geometry: (u32, u32), window: RenderWindow, + score: u64, } impl Game { pub fn new() -> Game { @@ -43,9 +45,33 @@ impl Game { Game{ tickrate: Duration::from_millis(1000), + low_tickrate: Duration::from_millis(200), maxfps: 30, window_geometry: geometry, window: window, + score: 0, + } + } + + pub fn get_score(&self) -> u64 { + self.score + } + pub fn set_score(&mut self, value: u64) { + if value > u64::MAX { + self.score = u64::MAX + } else { + self.score = value; + } + } + + pub fn get_tickrate(&self) -> Duration { + self.tickrate + } + pub fn set_tickrate(&mut self, duration: Duration) { + if duration < self.low_tickrate { + self.tickrate = self.low_tickrate + } else { + self.tickrate = duration } } @@ -90,6 +116,7 @@ impl Game { // Game setup let mut tetris = tetris::Tetris::new(); let mut piece = piece::Piece::random(piece::Pos(-2,3)); + let mut next_piece = piece::Piece::random(piece::Pos(3,13)); let mut key = None; 'main: loop { // Process events @@ -106,16 +133,25 @@ impl Game { // Check if piece is dead if piece.is_alive() == false { - piece.apply_to_grid(&mut tetris); - piece = piece::Piece::random(piece::Pos(-2,3)); - // piece = piece::Piece::new(piece::Pieces::Cube, piece::Pos(0,0)); + if piece.apply_to_grid(&mut tetris) == false { + // Game has been lost + break + } + piece = next_piece; + piece.set_pos(tetris::piece::Pos(-2, 3)); + next_piece = piece::Piece::random(piece::Pos(3,13)); } // Check if there are full lines - tetris.check_lines(); + match tetris.check_lines() { + 0 => (), + n => {self.set_score(self.get_score() + (n * n) as u64); + self.set_tickrate(self.get_tickrate() - Duration::from_millis(n as u64));}, + } + println!("{}, {:?}", self.get_score(), self.get_tickrate()); // Execute on tick - if tick.elapsed() >= self.tickrate { + if tick.elapsed() >= self.get_tickrate() { // Reset the clock tick = Instant::now(); @@ -179,6 +215,12 @@ impl Game { self.window.draw(&bit); } } + for piece_bit in next_piece.get_bits_pos() { + if !(piece_bit.0 < 0 || piece_bit.1 < 0) { + bit.set_position(((piece_bit.1 as f32) * 24.0, (piece_bit.0 as f32) * 24.0)); + self.window.draw(&bit); + } + } self.window.display(); } diff --git a/src/tetris.rs b/src/tetris.rs index c28a4b9..af0f579 100644 --- a/src/tetris.rs +++ b/src/tetris.rs @@ -28,9 +28,10 @@ impl Tetris { // Check each row of the grid // If one is full, remove it and drop // the rest of the grid down - pub fn check_lines(&mut self) { + pub fn check_lines(&mut self) -> u8 { // While there are full lines, continue to iterate let mut row = 19; + let mut total = 0; while row > 0 { let mut c = 0; for x in self.grid.get(row as usize).expect("Out of bounds") { @@ -45,11 +46,13 @@ impl Tetris { if c == 10 { self.grid.remove(row as usize); self.grid.insert(0, vec![0; 10]); + total += 1; continue; } row -= 1; } + return total } pub fn get_grid_pos(&self, pos: piece::Pos) -> i8 { diff --git a/src/tetris/piece.rs b/src/tetris/piece.rs index 4cfd68e..6454ab5 100644 --- a/src/tetris/piece.rs +++ b/src/tetris/piece.rs @@ -93,15 +93,15 @@ impl Pieces { fn get(&self) -> Vec> { let l: Vec> = vec![ // Outer most ring: top, right, bottom, left - vec![0,0,1,0,0, 0,0,0, 0,0,0,0,0, 0,0,0], + vec![0,0,0,0,0, 0,0,0, 0,0,0,0,0, 0,0,0], // Inner rign: top, right, bottom, left - vec![0,1,0, 0, 0,0,0, 1], + vec![0,1,0, 0, 0,1,1, 0], // Center ring. Is used as the center of rotation vec![1], ]; let r_l: Vec> = vec![ - vec![0,0,1,0,0, 0,0,0, 0,0,0,0,0, 0,0,0], - vec![0,1,0, 1, 0,0,0, 0], + vec![0,0,0,0,0, 0,0,0, 0,0,0,0,0, 0,0,0], + vec![0,1,0, 0, 1,1,0, 0], vec![1], ]; let cube: Vec> = vec![ @@ -150,14 +150,6 @@ pub struct Piece { alive: bool, } impl Piece { - pub fn new(p: Pieces, pos: Pos) -> Piece { - Piece{ - area: p.get(), - position: pos, - alive: true, - } - } - // Return a random piece // out of the enum Pieces pub fn random(pos: Pos) -> Piece { @@ -170,51 +162,31 @@ impl Piece { } // Get area as a 2d array - fn get_area(&self) -> [[i8; 5]; 5] { - let mut array = [[0; 5]; 5]; + fn get_area(&self) -> [[&i8; 5]; 5] { + let mut array = [[&0; 5]; 5]; for sections in &self.area { - if sections.len() == 16 { - // Top - array[0][0] = *sections.get(0).expect("Invalid"); - array[0][1] = *sections.get(1).expect("Invalid"); - array[0][2] = *sections.get(2).expect("Invalid"); - array[0][3] = *sections.get(3).expect("Invalid"); - array[0][4] = *sections.get(4).expect("Invalid"); - // Right - array[1][4] = *sections.get(5).expect("Invalid"); - array[2][4] = *sections.get(6).expect("Invalid"); - array[3][4] = *sections.get(7).expect("Invalid"); - // Bottom - array[4][4] = *sections.get(8).expect("Invalid"); - array[4][3] = *sections.get(9).expect("Invalid"); - array[4][2] = *sections.get(10).expect("Invalid"); - array[4][1] = *sections.get(11).expect("Invalid"); - array[4][0] = *sections.get(12).expect("Invalid"); - // Left - array[3][0] = *sections.get(13).expect("Invalid"); - array[2][0] = *sections.get(14).expect("Invalid"); - array[1][0] = *sections.get(15).expect("Invalid"); } - if sections.len() == 8 { - // Top - array[1][1] = *sections.get(0).expect("Invalid"); - array[1][2] = *sections.get(1).expect("Invalid"); - array[1][3] = *sections.get(2).expect("Invalid"); - // Right - array[2][3] = *sections.get(3).expect("Invalid"); - // Bottom - array[3][3] = *sections.get(4).expect("Invalid"); - array[3][2] = *sections.get(5).expect("Invalid"); - array[3][1] = *sections.get(6).expect("Invalid"); - // Left - array[2][1] = *sections.get(7).expect("Invalid"); + let len = sections.len(); + let mut y = [0; 16]; + let mut x = [0; 16]; + + if len == 16 { + y = [0,0,0,0,0,1,2,3,4,4,4,4,4,3,2,1]; + x = [0,1,2,3,4,4,4,4,4,3,2,1,0,0,0,0]; + } else if len == 8 { + y = [1,1,1,2,3,3,3,2,0,0,0,0,0,0,0,0]; + x = [1,2,3,3,3,2,1,1,0,0,0,0,0,0,0,0]; + } else if len == 1 { + y = [2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; + x = [2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; } - if sections.len() == 1 { - array[2][2] = *sections.get(0).expect("Invalid"); + + for c in 0..len { + array[y[c]][x[c]] = sections.get(c).expect("Invalid"); } } - return array + } // Using a grid and a direction; @@ -242,10 +214,17 @@ impl Piece { Ok(()) } - pub fn apply_to_grid(&self, grid: &mut Tetris) { + // Return false on kill + pub fn apply_to_grid(&mut self, grid: &mut Tetris) -> bool { for pos in self.get_bits_pos() { - grid.set_grid(pos, 1) + if pos.0 < 0 { + self.kill(); + return false + } else { + grid.set_grid(pos, 1) + } } + return true } fn apply_dir(&mut self, dir: &Dir) { @@ -260,7 +239,7 @@ impl Piece { let mut x = -1; for posx in posy { x += 1; - if posx == 1 { + if posx == &1 { piece_pos_vec.push(self.get_pos() + Pos(y, x)) } } @@ -324,6 +303,10 @@ impl Piece { self.position } + pub fn set_pos(&mut self, p: Pos) { + self.position = p; + } + pub fn is_alive(&self) -> bool { self.alive } @@ -336,9 +319,11 @@ impl Piece { pub fn r#move(&mut self, dir: Dir, grid: &Tetris) { // If a hit is detected, don't move // Otherwise move - match self.hit_detect(&dir, &grid) { - Ok(_) => self.apply_dir(&dir), - Err(_) => (), + if self.is_alive() { + match self.hit_detect(&dir, &grid) { + Ok(_) => self.apply_dir(&dir), + Err(_) => (), + } } } } @@ -349,7 +334,7 @@ mod tests { #[test] fn apply_down() { - let mut p = Piece::new(Pieces::Cube, Pos(0,0)); + let mut p = Piece::random(Pos(0,0)); let d = Dir::Down; p.apply_dir(&d); @@ -360,7 +345,7 @@ mod tests { #[test] fn hit_test() { - let mut p = Piece::new(Pieces::Cube, Pos(30,0)); + let mut p = Piece::random(Pos(30,0)); let d = Dir::Down; let tetris = Tetris::new(); @@ -374,7 +359,7 @@ mod tests { } #[test] fn hit_nothing_test() { - let mut p = Piece::new(Pieces::Cube, Pos(0,0)); + let mut p = Piece::random(Pos(0,0)); let d = Dir::Down; let tetris = Tetris::new(); -- cgit v1.2.3