mirror of
https://github.com/kristoferssolo/Tetris.git
synced 2025-10-21 20:00:35 +00:00
feat(game): add vertical block collision
This commit is contained in:
parent
a211dd0254
commit
e68abf8f94
@ -7,9 +7,10 @@ readme = "README.md"
|
|||||||
requires-python = ">=3.11"
|
requires-python = ">=3.11"
|
||||||
license = { text = "GPLv3" }
|
license = { text = "GPLv3" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"loguru==0.7.2",
|
|
||||||
"attrs==23.1.0",
|
"attrs==23.1.0",
|
||||||
|
"loguru==0.7.2",
|
||||||
"neat-python==0.92",
|
"neat-python==0.92",
|
||||||
|
"numpy==1.26.3",
|
||||||
"pygame-ce==2.4.0",
|
"pygame-ce==2.4.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
loguru>=0.7.2
|
|
||||||
attrs>=23.1.0
|
attrs>=23.1.0
|
||||||
|
loguru>=0.7.2
|
||||||
neat-python>=0.92
|
neat-python>=0.92
|
||||||
|
numpy>=1.26.3
|
||||||
pygame-ce>=2.4.0
|
pygame-ce>=2.4.0
|
||||||
.
|
.
|
||||||
|
|||||||
@ -1,10 +1,16 @@
|
|||||||
|
import numpy as np
|
||||||
import pygame
|
import pygame
|
||||||
from utils import CONFIG, Size
|
from utils import CONFIG, Size
|
||||||
|
|
||||||
|
|
||||||
class Block(pygame.sprite.Sprite):
|
class Block(pygame.sprite.Sprite):
|
||||||
def __init__(
|
def __init__(
|
||||||
self, /, *, group: pygame.sprite.Group, pos: pygame.Vector2, color: str
|
self,
|
||||||
|
/,
|
||||||
|
*,
|
||||||
|
group: pygame.sprite.Group,
|
||||||
|
pos: pygame.Vector2,
|
||||||
|
color: str,
|
||||||
) -> None:
|
) -> None:
|
||||||
super().__init__(group)
|
super().__init__(group)
|
||||||
self.image = pygame.Surface(CONFIG.game.cell)
|
self.image = pygame.Surface(CONFIG.game.cell)
|
||||||
@ -16,8 +22,8 @@ class Block(pygame.sprite.Sprite):
|
|||||||
def update(self) -> None:
|
def update(self) -> None:
|
||||||
self.rect.topleft = self.pos * CONFIG.game.cell.width
|
self.rect.topleft = self.pos * CONFIG.game.cell.width
|
||||||
|
|
||||||
def vertical_collision(self, x: int) -> bool:
|
def vertical_collision(self, x: int, field: np.ndarray) -> bool:
|
||||||
return not 0 <= x < CONFIG.game.columns
|
return not 0 <= x < CONFIG.game.columns or field[int(self.pos.y), x]
|
||||||
|
|
||||||
def horizontal_collision(self, y: int) -> bool:
|
def horizontal_collision(self, y: int) -> bool:
|
||||||
return y >= CONFIG.game.rows
|
return y >= CONFIG.game.rows
|
||||||
|
|||||||
@ -1,6 +1,10 @@
|
|||||||
import pygame
|
from typing import Optional
|
||||||
from utils import CONFIG, Direction, Figure
|
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
import pygame
|
||||||
|
from utils import CONFIG, Direction, Field, Figure
|
||||||
|
|
||||||
|
from .block import Block
|
||||||
from .log import log
|
from .log import log
|
||||||
from .tetromino import Tetromino
|
from .tetromino import Tetromino
|
||||||
from .timer import Timer, Timers
|
from .timer import Timer, Timers
|
||||||
@ -12,10 +16,17 @@ class Game:
|
|||||||
self.dispaly_surface = pygame.display.get_surface()
|
self.dispaly_surface = pygame.display.get_surface()
|
||||||
self.rect = self.surface.get_rect(topleft=CONFIG.game.pos)
|
self.rect = self.surface.get_rect(topleft=CONFIG.game.pos)
|
||||||
|
|
||||||
|
self.sprites: pygame.sprite.Group[Block] = pygame.sprite.Group()
|
||||||
|
|
||||||
self._create_grid_surface()
|
self._create_grid_surface()
|
||||||
|
|
||||||
self.sprites = pygame.sprite.Group()
|
self.field = np.full((CONFIG.game.rows, CONFIG.game.columns), None, dtype=Field)
|
||||||
self.tetromino = Tetromino(self.sprites, self.create_new_tetromino)
|
|
||||||
|
self.tetromino = Tetromino(
|
||||||
|
self.sprites,
|
||||||
|
self.create_new_tetromino,
|
||||||
|
self.field,
|
||||||
|
)
|
||||||
|
|
||||||
self.timers = Timers(
|
self.timers = Timers(
|
||||||
Timer(CONFIG.game.initial_speed, True, self.move_down),
|
Timer(CONFIG.game.initial_speed, True, self.move_down),
|
||||||
@ -63,7 +74,11 @@ class Game:
|
|||||||
self.tetromino.move_horizontal(Direction.RIGHT)
|
self.tetromino.move_horizontal(Direction.RIGHT)
|
||||||
|
|
||||||
def create_new_tetromino(self) -> None:
|
def create_new_tetromino(self) -> None:
|
||||||
self.tetromino = Tetromino(self.sprites, self.create_new_tetromino)
|
self.tetromino = Tetromino(
|
||||||
|
self.sprites,
|
||||||
|
self.create_new_tetromino,
|
||||||
|
self.field,
|
||||||
|
)
|
||||||
|
|
||||||
def _create_grid_surface(self) -> None:
|
def _create_grid_surface(self) -> None:
|
||||||
self.grid_surface = self.surface.copy()
|
self.grid_surface = self.surface.copy()
|
||||||
|
|||||||
@ -1,22 +1,26 @@
|
|||||||
from typing import Callable, Optional
|
from typing import Callable, Optional
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
import pygame
|
import pygame
|
||||||
from utils import CONFIG, Direction, Figure, FigureConfig, Size
|
from utils import CONFIG, Direction, Figure, FigureConfig, Size
|
||||||
|
|
||||||
from .block import Block
|
from .block import Block
|
||||||
|
from .log import log
|
||||||
|
|
||||||
|
|
||||||
class Tetromino:
|
class Tetromino:
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
group: pygame.sprite.Group,
|
group: pygame.sprite.Group,
|
||||||
func: Callable[[None], None],
|
func: Callable[[], None],
|
||||||
|
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: FigureConfig = shape.value if shape else Figure.random().value
|
||||||
self.block_positions: list[pygame.Vector2] = self.figure.shape
|
self.block_positions: list[pygame.Vector2] = self.figure.shape
|
||||||
self.color: str = self.figure.color
|
self.color: str = self.figure.color
|
||||||
self.create_new = func
|
self.create_new = func
|
||||||
|
self.field = field
|
||||||
|
|
||||||
self.blocks = [
|
self.blocks = [
|
||||||
Block(group=group, pos=pos, color=self.color)
|
Block(group=group, pos=pos, color=self.color)
|
||||||
@ -28,6 +32,8 @@ class Tetromino:
|
|||||||
for block in self.blocks:
|
for block in self.blocks:
|
||||||
block.pos.y += 1
|
block.pos.y += 1
|
||||||
else:
|
else:
|
||||||
|
for block in self.blocks:
|
||||||
|
self.field[int(block.pos.y), int(block.pos.x)] = block
|
||||||
self.create_new()
|
self.create_new()
|
||||||
|
|
||||||
def move_horizontal(self, direction: Direction) -> None:
|
def move_horizontal(self, direction: Direction) -> None:
|
||||||
@ -39,7 +45,7 @@ class Tetromino:
|
|||||||
self, blocks: list[Block], direction: Direction
|
self, blocks: list[Block], direction: Direction
|
||||||
) -> bool:
|
) -> bool:
|
||||||
return any(
|
return any(
|
||||||
block.vertical_collision(int(block.pos.x + direction.value))
|
block.vertical_collision(int(block.pos.x + direction.value), self.field)
|
||||||
for block in self.blocks
|
for block in self.blocks
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -8,7 +8,7 @@ from attrs import define, field
|
|||||||
class Timer:
|
class Timer:
|
||||||
duration: int = field(converter=int)
|
duration: int = field(converter=int)
|
||||||
repeated: bool = field(default=False)
|
repeated: bool = field(default=False)
|
||||||
func: Optional[Callable[[None], None]] = field(default=None)
|
func: Optional[Callable[[], None]] = field(default=None)
|
||||||
start_time: int = 0
|
start_time: int = 0
|
||||||
active: bool = False
|
active: bool = False
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
from .config import CONFIG
|
from .config import CONFIG
|
||||||
from .direction import Direction
|
from .enum import Direction, Field
|
||||||
from .figure import Figure, FigureConfig
|
from .figure import Figure, FigureConfig
|
||||||
from .log import log
|
from .log import log
|
||||||
from .path import BASE_PATH
|
from .path import BASE_PATH
|
||||||
@ -13,4 +13,5 @@ __all__ = [
|
|||||||
"Figure",
|
"Figure",
|
||||||
"FigureConfig",
|
"FigureConfig",
|
||||||
"Direction",
|
"Direction",
|
||||||
|
"Field",
|
||||||
]
|
]
|
||||||
|
|||||||
@ -6,3 +6,8 @@ class Direction(Enum):
|
|||||||
RIGHT = 1
|
RIGHT = 1
|
||||||
DOWN = 1
|
DOWN = 1
|
||||||
UP = -1
|
UP = -1
|
||||||
|
|
||||||
|
|
||||||
|
class Field(Enum):
|
||||||
|
EMPTY = None
|
||||||
|
FILLED = "Block"
|
||||||
@ -9,7 +9,7 @@ from .colors import TokyoNightNight
|
|||||||
|
|
||||||
|
|
||||||
class FigureConfig(NamedTuple):
|
class FigureConfig(NamedTuple):
|
||||||
shape: list[Vec2, Vec2, Vec2, Vec2]
|
shape: list[Vec2]
|
||||||
color: str
|
color: str
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user