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)
}
pub fn colliding(
pub fn lowest_y(
&self,
CurrentTetromino {
tetromino,
direction,
x: cur_x,
y: cur_y,
x,
y,
}: &CurrentTetromino,
) -> bool {
) -> i8 {
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() {
for x in row
fn pattern_and_position_colliding(&self, pattern: [[bool; 4]; 4], x: i8, y: i8) -> bool {
for (y_offset, row) in pattern.iter().enumerate() {
for x_offset in row
.iter()
.enumerate()
.filter(|(_, exists)| **exists)
.map(|(x, _)| x)
{
let x = x as i8 + cur_x;
let y = y as i8 + cur_y;
let x = x_offset as i8 + x;
let y = y_offset as i8 + y;
if y < 0 {
continue;
@ -70,6 +79,19 @@ impl Board {
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 {
let line_clears: Vec<_> = self
.iter()

View File

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