feat(game): add figure rotation

This commit is contained in:
Kristofers Solo 2024-01-04 04:46:50 +02:00
parent 2df1c0a156
commit 2c040b4575
4 changed files with 57 additions and 10 deletions

View File

@ -27,3 +27,6 @@ class Block(pygame.sprite.Sprite):
def horizontal_collision(self, y: int, field: np.ndarray) -> bool: def horizontal_collision(self, y: int, field: np.ndarray) -> bool:
return y >= CONFIG.game.rows or (y >= 0 and field[y, int(self.pos.x)]) return y >= CONFIG.game.rows or (y >= 0 and field[y, int(self.pos.x)])
def rotate(self, pivot: pygame.Vector2) -> pygame.Vector2:
return pivot + (self.pos - pivot).rotate(90)

View File

@ -31,6 +31,7 @@ class Game:
self.timers = Timers( self.timers = Timers(
Timer(CONFIG.game.initial_speed, True, self.move_down), Timer(CONFIG.game.initial_speed, True, self.move_down),
Timer(CONFIG.game.movment_delay), Timer(CONFIG.game.movment_delay),
Timer(CONFIG.game.rotation_delay),
) )
self.timers.vertical.activate() self.timers.vertical.activate()
@ -64,6 +65,17 @@ class Game:
self.move_right() self.move_right()
self.timers.horizontal.activate() self.timers.horizontal.activate()
if not self.timers.rotation.active:
if (
keys[pygame.K_SPACE]
or keys[pygame.K_r]
or keys[pygame.K_UP]
or keys[pygame.K_w]
or keys[pygame.K_k]
):
self.tetromino.rotate()
self.timers.rotation.activate()
def move_down(self) -> None: def move_down(self) -> None:
self.tetromino.move_down() self.tetromino.move_down()
@ -131,13 +143,15 @@ class Game:
self._delete_rows(delete_rows) self._delete_rows(delete_rows)
def _delete_rows(self, delete_rows: list[int]) -> None: def _delete_rows(self, delete_rows: list[int]) -> None:
if delete_rows: if not delete_rows:
for row in delete_rows: return
for block in self.field[row]:
block.kill()
self._move_rows_down(row) for row in delete_rows:
self._rebuild_field() for block in self.field[row]:
block.kill()
self._move_rows_down(row)
self._rebuild_field()
def _move_rows_down(self, deleted_row: int) -> None: def _move_rows_down(self, deleted_row: int) -> None:
for row in self.field: for row in self.field:

View File

@ -2,7 +2,7 @@ from typing import Callable, Optional
import numpy as np import numpy as np
import pygame import pygame
from utils import CONFIG, Direction, Figure, FigureConfig, Size from utils import CONFIG, Direction, Figure, Size
from .block import Block from .block import Block
from .log import log from .log import log
@ -16,9 +16,9 @@ class Tetromino:
field: np.ndarray, field: np.ndarray,
shape: Optional[Figure] = None, shape: Optional[Figure] = None,
) -> None: ) -> None:
self.figure: FigureConfig = shape.value if shape else Figure.random().value self.figure: Figure = shape if shape else Figure.random()
self.block_positions: list[pygame.Vector2] = self.figure.shape self.block_positions: list[pygame.Vector2] = self.figure.value.shape
self.color: str = self.figure.color self.color: str = self.figure.value.color
self.create_new = func self.create_new = func
self.field = field self.field = field
@ -41,6 +41,21 @@ class Tetromino:
for block in self.blocks: for block in self.blocks:
block.pos.x += direction.value block.pos.x += direction.value
def rotate(self) -> None:
if self.figure == Figure.O:
return
pivot: pygame.Vector2 = self.blocks[0].pos
new_positions: list[pygame.Vector2] = [
block.rotate(pivot) for block in self.blocks
]
if not self._are_new_positions_valid(new_positions):
return
self._update_block_positions(new_positions)
def _check_vertical_collision( def _check_vertical_collision(
self, blocks: list[Block], direction: Direction self, blocks: list[Block], direction: Direction
) -> bool: ) -> bool:
@ -56,3 +71,17 @@ class Tetromino:
block.horizontal_collision(int(block.pos.y + direction.value), self.field) block.horizontal_collision(int(block.pos.y + direction.value), self.field)
for block in self.blocks for block in self.blocks
) )
def _are_new_positions_valid(self, new_positions: list[pygame.Vector2]) -> bool:
for pos in new_positions:
if not (
0 <= pos.x < CONFIG.game.columns and 0 <= pos.y <= CONFIG.game.rows
):
return False
if self.field[int(pos.y), int(pos.x)]:
return False
return True
def _update_block_positions(self, new_positions: list[pygame.Vector2]) -> None:
for block, new_pos in zip(self.blocks, new_positions):
block.pos = new_pos

View File

@ -35,3 +35,4 @@ class Timer:
class Timers(NamedTuple): class Timers(NamedTuple):
vertical: Timer vertical: Timer
horizontal: Timer horizontal: Timer
rotation: Timer