tetris/src/graphics/standard_renderer.rs

140 lines
4.3 KiB
Rust

use crate::{
game::Game,
graphics::{MinoColor, Renderable, BORDER_RADIUS, CELL_SIZE, COLOR_BACKGROUND, UI_PADDING},
playfield::{PlayField, PLAYFIELD_HEIGHT, PLAYFIELD_WIDTH},
tetromino::{Position, RotationState, Tetromino, TetrominoType},
};
use log::error;
use sdl2::{
pixels::Color,
rect::Rect,
render::{Canvas, RenderTarget},
video::Window,
};
pub fn render(canvas: &mut Canvas<Window>, game: &Game) {
let (x, y) = canvas.window().size();
let game_width = game.width() as i32;
let game_height = game.height() as i32;
canvas.set_viewport(Some(Rect::new(
x as i32 / 2 - game_width / 2 as i32,
y as i32 / 2 - game_height / 2 as i32,
game_width as u32,
game_height as u32,
)));
match game.render(canvas) {
Ok(_) => (),
Err(e) => error!("{}", e),
};
}
impl Renderable for Game {
fn width(&self) -> usize {
self.playfield().width()
}
fn height(&self) -> usize {
self.playfield().height()
}
fn render<R: RenderTarget>(&self, canvas: &mut Canvas<R>) -> Result<(), String> {
self.playfield().render(canvas)
}
}
impl Renderable for PlayField {
fn width(&self) -> usize {
(CELL_SIZE as usize) * PLAYFIELD_WIDTH
}
fn height(&self) -> usize {
(CELL_SIZE as usize) * PLAYFIELD_HEIGHT
}
fn render<R: RenderTarget>(&self, canvas: &mut Canvas<R>) -> Result<(), String> {
for y in 0..PLAYFIELD_HEIGHT {
for x in 0..PLAYFIELD_WIDTH {
canvas.set_draw_color(Color::RGB(0, 0, 0));
canvas.fill_rect(Rect::new(
CELL_SIZE as i32 * x as i32,
CELL_SIZE as i32 * y as i32,
CELL_SIZE,
CELL_SIZE,
))?;
match self.field()[y + PLAYFIELD_HEIGHT][x] {
Some(mino) => canvas.set_draw_color(mino),
None => canvas.set_draw_color(COLOR_BACKGROUND),
}
canvas.fill_rect(Rect::new(
CELL_SIZE as i32 * x as i32 + BORDER_RADIUS as i32,
CELL_SIZE as i32 * y as i32 + BORDER_RADIUS as i32,
CELL_SIZE - 2 * BORDER_RADIUS,
CELL_SIZE - 2 * BORDER_RADIUS,
))?;
}
}
match self.hold_piece() {
Some(p) => {
canvas.set_draw_color(p);
canvas.fill_rect(Rect::new(-32 - UI_PADDING as i32, 0, CELL_SIZE, CELL_SIZE))?;
}
None => (),
}
match self.active_piece {
Some(piece) => piece.render(canvas)?,
None => (),
}
Ok(())
}
}
impl Renderable for Tetromino {
fn width(&self) -> usize {
CELL_SIZE as usize
* match self.rotation_state {
RotationState::O | RotationState::U => match self.piece_type {
TetrominoType::I => 4,
TetrominoType::O => 2,
_ => 3,
},
RotationState::L | RotationState::R => match self.piece_type {
TetrominoType::I => 1,
_ => 2,
},
}
}
fn height(&self) -> usize {
CELL_SIZE as usize
* match self.rotation_state {
RotationState::O | RotationState::U => match self.piece_type {
TetrominoType::I => 1,
_ => 2,
},
RotationState::L | RotationState::R => match self.piece_type {
TetrominoType::I => 4,
TetrominoType::O => 2,
_ => 3,
},
}
}
fn render<R: RenderTarget>(&self, canvas: &mut Canvas<R>) -> Result<(), String> {
for Position { x, y } in self.get_cur_occupied_spaces() {
canvas.set_draw_color::<MinoColor>(self.piece_type.into());
let height = y as isize - PLAYFIELD_HEIGHT as isize;
canvas.fill_rect(Rect::new(
CELL_SIZE as i32 * x as i32 + BORDER_RADIUS as i32,
CELL_SIZE as i32 * height as i32 + BORDER_RADIUS as i32,
CELL_SIZE - 2 * BORDER_RADIUS,
CELL_SIZE - 2 * BORDER_RADIUS,
))?;
}
Ok(())
}
}