diff options
author | Oxore <oxore@protonmail.com> | 2023-08-01 23:30:27 +0300 |
---|---|---|
committer | Oxore <oxore@protonmail.com> | 2023-08-01 23:32:49 +0300 |
commit | b65e091d2397bcceb66099f81533810c3157528a (patch) | |
tree | 92f6cb28e96c7d59afcd42ca29063f9c6a87e586 | |
parent | ce039cad28945e23c89b193bb24cb63c06963640 (diff) |
Fix flickering by disabling cursor, introduce TUI struct
-rw-r--r-- | src/main.rs | 226 |
1 files changed, 126 insertions, 100 deletions
diff --git a/src/main.rs b/src/main.rs index 57da584..f8002f0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -388,143 +388,169 @@ impl Game { } } -fn display_hold(figure: &Figure, y_global: usize) { - let offset = DISPLAY_HOLD_OFFSET_DOWN; - let at_figure = y_global >= (1 + offset) && y_global < FIGURE_SIZE_ROWS + (1 + offset); - if y_global == offset { - print!(" Hold: "); - } else if at_figure { - print!(" "); - let y = FIGURE_SIZE_ROWS - 1 - (y_global - 1 - offset); - for x in 0..FIGURE_SIZE_COLS { - let c = figure.cells[y * FIGURE_SIZE_COLS + x]; - if c == 0 { - print!(" "); - } else { - print!("██"); +struct TUI { + state: termios::Termios, +} + +impl TUI { + fn display_hold(&self, figure: &Figure, y_global: usize) { + let offset = DISPLAY_HOLD_OFFSET_DOWN; + let at_figure = y_global >= (1 + offset) && y_global < FIGURE_SIZE_ROWS + (1 + offset); + if y_global == offset { + print!(" Hold: "); + } else if at_figure { + print!(" "); + let y = FIGURE_SIZE_ROWS - 1 - (y_global - 1 - offset); + for x in 0..FIGURE_SIZE_COLS { + let c = figure.cells[y * FIGURE_SIZE_COLS + x]; + if c == 0 { + print!(" "); + } else { + print!("██"); + } } + print!(" "); + } else { + print!(" "); } - print!(" "); - } else { - print!(" "); } -} -fn display_next(figure: &[Figure; NEXT_COUNT], y_global: usize) { - let offset = DISPLAY_NEXT_OFFSET_DOWN; - if y_global == offset { - print!(" Next: "); - } else { - for i in 0..NEXT_COUNT { - let at_figure = y_global >= (1 + offset + FIGURE_SIZE_ROWS * i) && y_global < (1 + offset + FIGURE_SIZE_ROWS * (i + 1)); - if at_figure { - print!(" "); - let y = FIGURE_SIZE_ROWS - 1 - (y_global - 1 - offset - FIGURE_SIZE_ROWS * i); - for x in 0..FIGURE_SIZE_COLS { - let c = figure[i].cells[y * FIGURE_SIZE_COLS + x]; - if c == 0 { - print!(" "); - } else { - print!("██"); + fn display_next(&self, figure: &[Figure; NEXT_COUNT], y_global: usize) { + let offset = DISPLAY_NEXT_OFFSET_DOWN; + if y_global == offset { + print!(" Next: "); + } else { + for i in 0..NEXT_COUNT { + let at_figure = y_global >= (1 + offset + FIGURE_SIZE_ROWS * i) && y_global < (1 + offset + FIGURE_SIZE_ROWS * (i + 1)); + if at_figure { + print!(" "); + let y = FIGURE_SIZE_ROWS - 1 - (y_global - 1 - offset - FIGURE_SIZE_ROWS * i); + for x in 0..FIGURE_SIZE_COLS { + let c = figure[i].cells[y * FIGURE_SIZE_COLS + x]; + if c == 0 { + print!(" "); + } else { + print!("██"); + } } + break; } - break; } } } -} -fn display_field(field: &Field, y: usize) { - print!("|"); - for x in 0..FIELD_COLS { - let color = field.cells[(FIELD_ROWS_VISIBLE - 1 - y) * FIELD_COLS + x] & !GHOST_MASK; - let ghost = field.cells[(FIELD_ROWS_VISIBLE - 1 - y) * FIELD_COLS + x] & GHOST_MASK != 0; - if color == 0 { - print!(" "); - } else if ghost { - print!("░░"); + fn display_field(&self, field: &Field, y: usize) { + print!("|"); + for x in 0..FIELD_COLS { + let color = field.cells[(FIELD_ROWS_VISIBLE - 1 - y) * FIELD_COLS + x] & !GHOST_MASK; + let ghost = field.cells[(FIELD_ROWS_VISIBLE - 1 - y) * FIELD_COLS + x] & GHOST_MASK != 0; + if color == 0 { + print!(" "); + } else if ghost { + print!("░░"); + } else { + print!("██"); + } + } + print!("|"); + } + + fn display_game(&self, game: &Game) { + self.cursor_to_home(); + let mut field = game.field.clone(); + let mut ghost = game.figure.clone(); + for i in 0..FIGURE_SIZE { + ghost.cells[i] |= GHOST_MASK; + } + let mut y_ghost = game.y; + while !field.has_collision(&ghost, game.x, y_ghost) { + y_ghost -= 1; + } + y_ghost += 1; + field.render(&ghost, game.x, y_ghost); + field.render(&game.figure, game.x, game.y); + for y in 0..FIELD_ROWS_VISIBLE { + self.display_hold(&game.figure_on_hold, y); + self.display_field(&field, y); + self.display_next(&game.figure_next, y); + print!("\r\x1b[1B"); + } + if game.field.has_collision(&game.figure, game.x, game.y) { + println!("Collision!"); } else { - print!("██"); + self.clear_line(); } } - print!("|"); -} -fn display_game(game: &Game) { - cursor_to_home(); - let mut field = game.field.clone(); - let mut ghost = game.figure.clone(); - for i in 0..FIGURE_SIZE { - ghost.cells[i] |= GHOST_MASK; - } - let mut y_ghost = game.y; - while !field.has_collision(&ghost, game.x, y_ghost) { - y_ghost -= 1; - } - y_ghost += 1; - field.render(&ghost, game.x, y_ghost); - field.render(&game.figure, game.x, game.y); - for y in 0..FIELD_ROWS_VISIBLE { - display_hold(&game.figure_on_hold, y); - display_field(&field, y); - display_next(&game.figure_next, y); - print!("\r\x1b[1B"); - } - if game.field.has_collision(&game.figure, game.x, game.y) { - println!("Collision!"); - } else { - clear_line(); + fn clear_screen(&self) { + print!("\x1B[2J"); + } + + fn cursor_to_home(&self) { + print!("\x1B[H"); + } + + fn clear_line(&self) { + println!("\x1B[2K"); + } + + fn hide_cursor(&self) { + println!("\x1B[?25l"); } -} -fn clear_screen() { - print!("\x1B[2J"); + fn show_cursor(&self) { + println!("\x1B[?25h"); + } } -fn cursor_to_home() { - print!("\x1B[H"); +impl Default for TUI { + fn default() -> Self { + let termios_state_initial = termios::Termios::from_fd(0).unwrap(); + let mut termios_state = termios_state_initial.clone(); + let c_lflag = termios_state.c_lflag; + termios_state.c_lflag &= !(termios::ICANON | termios::ECHO); + termios::tcsetattr(0, termios::TCSADRAIN, &termios_state).unwrap(); + termios_state.c_lflag = c_lflag; + let tui = Self{state: termios_state_initial}; + tui.clear_screen(); + tui.hide_cursor(); + tui + } } -fn clear_line() { - println!("\x1B[2K"); +impl Drop for TUI { + fn drop(&mut self) { + self.show_cursor(); + termios::tcsetattr(0, termios::TCSADRAIN, &self.state).unwrap(); + } } fn main() { - let termios_state_initial = termios::Termios::from_fd(0).unwrap(); - let mut termios_state = termios_state_initial.clone(); - let c_lflag = termios_state.c_lflag; - termios_state.c_lflag &= !(termios::ICANON | termios::ECHO); - termios::tcsetattr(0, termios::TCSADRAIN, &termios_state).unwrap(); - termios_state.c_lflag = c_lflag; - clear_screen(); + let tui = TUI::default(); let mut game = Game::default(); - display_game(&game); + tui.display_game(&game); let mut noblock_stdin = NonBlockingReader::from_fd(std::io::stdin()).unwrap(); 'outer: while !noblock_stdin.is_eof() { let mut buf = String::new(); noblock_stdin.read_available_to_string(&mut buf).unwrap(); let mut changed = false; - if buf.len() > 0 { - for c in buf.bytes() { - if let Some(result) = game.step(Some(c as char)) { - match result { - StepResult::StateChanged => changed = true, - StepResult::Quit => break 'outer, - } - } - } - } else { - if let Some(result) = game.step(None) { + for c in buf.bytes() { + if let Some(result) = game.step(Some(c as char)) { match result { StepResult::StateChanged => changed = true, StepResult::Quit => break 'outer, } } } + if let Some(result) = game.step(None) { + match result { + StepResult::StateChanged => changed = true, + StepResult::Quit => break 'outer, + } + } if changed { - display_game(&game); + tui.display_game(&game); } std::thread::sleep(std::time::Duration::from_millis(1)); } - termios::tcsetattr(0, termios::TCSADRAIN, &termios_state_initial).unwrap(); } |