draw ghost

This commit is contained in:
Theis Pieter Hollebeek 2025-03-03 15:14:59 +01:00
parent fc6ebcdbc2
commit 7d6822cd34
2 changed files with 128 additions and 70 deletions

View File

@ -28,26 +28,35 @@ impl Board {
Board(board) Board(board)
} }
pub fn colliding( pub fn lowest_y(
&self, &self,
CurrentTetromino { CurrentTetromino {
tetromino, tetromino,
direction, direction,
x: cur_x, x,
y: cur_y, y,
}: &CurrentTetromino, }: &CurrentTetromino,
) -> bool { ) -> i8 {
let pattern = tetromino.direction_pattern(direction); let pattern = tetromino.direction_pattern(direction);
let mut y = *y;
loop {
if self.pattern_and_position_colliding(pattern, *x, y) {
break y - 1;
}
y += 1;
}
}
for (y, row) in pattern.iter().enumerate() { fn pattern_and_position_colliding(&self, pattern: [[bool; 4]; 4], x: i8, y: i8) -> bool {
for x in row for (y_offset, row) in pattern.iter().enumerate() {
for x_offset in row
.iter() .iter()
.enumerate() .enumerate()
.filter(|(_, exists)| **exists) .filter(|(_, exists)| **exists)
.map(|(x, _)| x) .map(|(x, _)| x)
{ {
let x = x as i8 + cur_x; let x = x_offset as i8 + x;
let y = y as i8 + cur_y; let y = y_offset as i8 + y;
if y < 0 { if y < 0 {
continue; continue;
@ -70,6 +79,19 @@ impl Board {
false false
} }
pub fn colliding(
&self,
CurrentTetromino {
tetromino,
direction,
x,
y,
}: &CurrentTetromino,
) -> bool {
let pattern = tetromino.direction_pattern(direction);
self.pattern_and_position_colliding(pattern, *x, *y)
}
pub fn lines_cleared(&mut self) -> usize { pub fn lines_cleared(&mut self) -> usize {
let line_clears: Vec<_> = self let line_clears: Vec<_> = self
.iter() .iter()

View File

@ -1,42 +1,85 @@
use crate::actions::{Action, ActionsHeld}; use crate::actions::{Action, ActionsHeld};
use crate::board::Board; use crate::board::Board;
use crate::game::{CurrentTetromino, Game}; use crate::game::{CurrentTetromino, Game};
use crate::tetromino::Tetromino;
use crate::Rgb; use crate::Rgb;
use sdl2::event::Event; use sdl2::event::Event;
use sdl2::keyboard::Keycode; use sdl2::keyboard::Keycode;
use sdl2::pixels::Color; use sdl2::pixels::Color;
use sdl2::rect::Rect; use sdl2::rect::Rect;
use sdl2::render::{Canvas, RenderTarget, Texture, TextureCreator, WindowCanvas}; use sdl2::render::{Texture, TextureCreator, WindowCanvas};
use sdl2::rwops::RWops; use sdl2::rwops::RWops;
use sdl2::ttf::Sdl2TtfContext; use sdl2::ttf::Sdl2TtfContext;
use std::time::Duration; use std::time::Duration;
fn draw_board_tile(canvas: &mut WindowCanvas, width: usize, height: usize, color: Rgb) { const WIDTH: i32 = 1000;
const HEIGHT: i32 = 800;
fn draw_board_tile(
canvas: &mut WindowCanvas,
width: usize,
height: usize,
color: &Rgb,
filled: bool,
) -> Result<(), String> {
canvas.set_draw_color(Color::RGB(color.0, color.1, color.2)); canvas.set_draw_color(Color::RGB(color.0, color.1, color.2));
canvas let rect = Rect::new(
.fill_rect(Rect::new( center(24 * Board::WIDTH as i32, WIDTH) + width as i32 * 24,
center(24 * Board::WIDTH as i32, 800) + width as i32 * 24, center(24 * Board::HEIGHT as i32, HEIGHT) + height as i32 * 24,
center(24 * Board::HEIGHT as i32, 600) + height as i32 * 24, 24,
24, 24,
24, );
)) if filled {
.unwrap(); canvas.fill_rect(rect)
} else {
canvas.draw_rect(rect)
}
} }
fn center(length: i32, max: i32) -> i32 { fn center(length: i32, max: i32) -> i32 {
(max - length) / 2 (max - length) / 2
} }
fn draw_board(canvas: &mut WindowCanvas, board: &Board, current: &CurrentTetromino) { fn draw_tetromino_from_parts(
canvas: &mut WindowCanvas,
x: i8,
y: i8,
color: Rgb,
pattern: [[bool; 4]; 4],
filled: bool,
) -> Result<(), String> {
for (y_offset, row) in pattern.iter().enumerate() {
for x_offset in row
.iter()
.enumerate()
.filter(|(_, exists)| **exists)
.map(|(x, _)| x)
{
let x = x_offset as i8 + x;
let y = y_offset as i8 + y;
if y < 0 {
continue;
}
draw_board_tile(canvas, x as usize, y as usize, &color, filled)?
}
}
Ok(())
}
fn draw_board(
canvas: &mut WindowCanvas,
board: &Board,
current: &CurrentTetromino,
) -> Result<(), String> {
canvas.set_draw_color(Color::WHITE); canvas.set_draw_color(Color::WHITE);
canvas canvas.draw_rect(Rect::new(
.draw_rect(Rect::new( center(24 * Board::WIDTH as i32, WIDTH) - 1,
center(24 * Board::WIDTH as i32, 800) - 1, center(24 * Board::HEIGHT as i32, HEIGHT) - 1,
center(24 * Board::HEIGHT as i32, 600) - 1, 24 * Board::WIDTH as u32 + 2,
24 * Board::WIDTH as u32 + 2, 24 * Board::HEIGHT as u32 + 2,
24 * Board::HEIGHT as u32 + 2, ))?;
))
.unwrap();
for (y, row) in board.iter().enumerate() { for (y, row) in board.iter().enumerate() {
for (x, piece) in row.iter().enumerate() { for (x, piece) in row.iter().enumerate() {
@ -44,53 +87,48 @@ fn draw_board(canvas: &mut WindowCanvas, board: &Board, current: &CurrentTetromi
Some(t) => Rgb::from_tetromino(t), Some(t) => Rgb::from_tetromino(t),
None => Rgb(0, 0, 0), None => Rgb(0, 0, 0),
}; };
draw_board_tile(canvas, x, y, color) draw_board_tile(canvas, x, y, &color, true)?
} }
} }
let pattern = current.tetromino.direction_pattern(&current.direction); let pattern = current.tetromino.direction_pattern(&current.direction);
for (y, row) in pattern.iter().enumerate() { draw_tetromino_from_parts(
for x in row canvas,
.iter() current.x,
.enumerate() board.lowest_y(&current),
.filter(|(_, exists)| **exists) Rgb(255, 255, 255),
.map(|(x, _)| x) pattern,
{ false,
let x = x as i8 + current.x; )?;
let y = y as i8 + current.y;
if y < 0 { draw_tetromino_from_parts(
continue; canvas,
} current.x,
current.y,
Rgb::from_tetromino(&current.tetromino),
pattern,
true,
)?;
draw_board_tile( Ok(())
canvas,
x as usize,
y as usize,
Rgb::from_tetromino(&current.tetromino),
)
}
}
} }
fn font_texture<'font, 'a, C>( fn font_texture<'font, 'a, C>(
text: &'a str, text: &'a str,
ttf_context: &'a Sdl2TtfContext, ttf_context: &'a Sdl2TtfContext,
texture_creator: &'font TextureCreator<C>, texture_creator: &'font TextureCreator<C>,
) -> Texture<'font> { ) -> Result<Texture<'font>, String> {
let font = ttf_context let font = ttf_context.load_font_from_rwops(
.load_font_from_rwops( RWops::from_bytes(include_bytes!("res/josenfin_sans_regular.ttf"))?,
RWops::from_bytes(include_bytes!("res/josenfin_sans_regular.ttf")).unwrap(), 24,
24, )?;
)
.unwrap();
let game_over_text = font.render(text).solid(Color::RGB(255, 255, 255)).unwrap(); let game_over_text = font.render(text).solid(Color::RGB(255, 255, 255)).unwrap();
let texture = texture_creator let texture = texture_creator
.create_texture_from_surface(game_over_text) .create_texture_from_surface(game_over_text)
.unwrap(); .unwrap();
texture Ok(texture)
} }
fn draw_important_text( fn draw_important_text(
@ -99,14 +137,14 @@ fn draw_important_text(
ttf_context: &Sdl2TtfContext, ttf_context: &Sdl2TtfContext,
) -> Result<(), String> { ) -> Result<(), String> {
let texture_creator = canvas.texture_creator(); let texture_creator = canvas.texture_creator();
let texture = font_texture(text, &ttf_context, &texture_creator); let texture = font_texture(text, &ttf_context, &texture_creator)?;
let size = texture.query(); let size = texture.query();
let width = size.width; let width = size.width;
let height = size.height; let height = size.height;
let x = center(width as i32, 800); let x = center(width as i32, WIDTH);
let y = center(height as i32, 600); let y = center(height as i32, HEIGHT);
canvas.set_draw_color(Color::WHITE); canvas.set_draw_color(Color::WHITE);
canvas.draw_rect(Rect::new(x - 9, y - 9, width + 18, height + 18))?; canvas.draw_rect(Rect::new(x - 9, y - 9, width + 18, height + 18))?;
@ -118,23 +156,23 @@ fn draw_important_text(
Ok(()) Ok(())
} }
pub fn start_game() { pub fn start_game() -> Result<(), String> {
let mut game = Game::new(); let mut game = Game::new();
let mut actions = ActionsHeld::new(); let mut actions = ActionsHeld::new();
let mut paused = false; let mut paused = false;
let sdl_context = sdl2::init().unwrap(); let sdl_context = sdl2::init()?;
let ttf_context = sdl2::ttf::init().unwrap(); let ttf_context = sdl2::ttf::init().unwrap();
let video_subsystem = sdl_context.video().unwrap(); let video_subsystem = sdl_context.video()?;
let window = video_subsystem let window = video_subsystem
.window("reimtris2", 800, 600) .window("reimtris2", WIDTH as u32, HEIGHT as u32)
.position_centered() .position_centered()
.build() .build()
.unwrap(); .unwrap();
let mut canvas = window.into_canvas().build().unwrap(); let mut canvas = window.into_canvas().build().unwrap();
let mut event_pump = sdl_context.event_pump().unwrap(); let mut event_pump = sdl_context.event_pump()?;
'running: loop { 'running: loop {
canvas.set_draw_color(Color::RGB(16, 16, 16)); canvas.set_draw_color(Color::RGB(16, 16, 16));
canvas.clear(); canvas.clear();
@ -144,7 +182,7 @@ pub fn start_game() {
| Event::KeyDown { | Event::KeyDown {
keycode: Some(Keycode::Escape), keycode: Some(Keycode::Escape),
.. ..
} => break 'running, } => break 'running Ok(()),
Event::KeyDown { Event::KeyDown {
keycode: Some(keycode), keycode: Some(keycode),
.. ..
@ -189,22 +227,20 @@ pub fn start_game() {
} }
} }
draw_board(&mut canvas, &game.board, &game.current_tetromino); draw_board(&mut canvas, &game.board, &game.current_tetromino)?;
if paused { if paused {
draw_important_text( draw_important_text(
"game paused o_o... press [p] to unpause !!", "game paused o_o... press [p] to unpause !!",
&mut canvas, &mut canvas,
&ttf_context, &ttf_context,
) )?;
.unwrap();
} else if game.game_over { } else if game.game_over {
draw_important_text( draw_important_text(
"game over T_T... press [enter] 2 restart :D", "game over T_T... press [enter] 2 restart :D",
&mut canvas, &mut canvas,
&ttf_context, &ttf_context,
) )?;
.unwrap();
} else { } else {
game.step(&actions); game.step(&actions);
} }