feat(game): add vertical block collision

This commit is contained in:
Kristofers Solo 2024-01-04 03:56:45 +02:00
parent a211dd0254
commit e68abf8f94
9 changed files with 50 additions and 15 deletions

View File

@ -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",
] ]

View File

@ -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
. .

View File

@ -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

View File

@ -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()

View File

@ -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
) )

View File

@ -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

View File

@ -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",
] ]

View File

@ -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"

View File

@ -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