mirror of
https://github.com/kristoferssolo/Tetris.git
synced 2025-10-21 20:00:35 +00:00
feat(game): add main menu
This commit is contained in:
parent
0afe1ed3cb
commit
7d5bf8e658
11
main.py
11
main.py
@ -61,16 +61,17 @@ def main(args: argparse.ArgumentParser) -> None:
|
||||
elif args.verbose:
|
||||
CONFIG.log_level = "info"
|
||||
|
||||
import ai
|
||||
# import ai
|
||||
import game
|
||||
|
||||
if args.train is not None:
|
||||
ai.log.debug("Training the AI")
|
||||
# ai.train(*args.train)
|
||||
game.Game(GameMode.AI_TRAINING).run()
|
||||
# ai.log.debug("Training the AI")
|
||||
# # ai.train(*args.train)
|
||||
# game.Menu(GameMode.AI_TRAINING).run()
|
||||
pass
|
||||
else:
|
||||
game.log.debug("Running the game")
|
||||
game.Game(GameMode.PLAYER).run()
|
||||
game.Main(GameMode.PLAYER).run()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
from .log import log
|
||||
from .screens import Game, Menu, Tetris
|
||||
from .screens import Game, Main, Tetris
|
||||
|
||||
__all__ = [
|
||||
"log",
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
from .game import Game
|
||||
from .menu import Menu
|
||||
from .main import Main
|
||||
from .preview import Preview
|
||||
from .score import Score
|
||||
from .tetris import Tetris
|
||||
|
||||
__all__ = ["Tetris", "Game", "Preview", "Score", "Menu"]
|
||||
__all__ = ["Tetris", "Game", "Preview", "Score", "Main"]
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
from abc import ABC, ABCMeta, abstractmethod
|
||||
|
||||
import pygame
|
||||
|
||||
|
||||
class BaseScreen(ABC, metaclass=ABCMeta):
|
||||
"""Base screen class."""
|
||||
@ -37,7 +35,7 @@ class SceenElement(ABC, metaclass=ABCMeta):
|
||||
"""Initialize the rectangle."""
|
||||
|
||||
@abstractmethod
|
||||
def _update_diplaysurface(self) -> None:
|
||||
def _update_display_surface(self) -> None:
|
||||
"""Update the display surface."""
|
||||
|
||||
|
||||
|
||||
20
src/game/screens/button.py
Normal file
20
src/game/screens/button.py
Normal file
@ -0,0 +1,20 @@
|
||||
from abc import ABC, ABCMeta, abstractmethod
|
||||
from typing import Callable, Optional
|
||||
|
||||
import pygame
|
||||
|
||||
|
||||
class Button(ABC, metaclass=ABCMeta):
|
||||
"""Base button class."""
|
||||
|
||||
def __init__(self, text: str, action: Optional[Callable[[], None]]) -> None:
|
||||
self.action = action
|
||||
self.text = text
|
||||
|
||||
@abstractmethod
|
||||
def on_click(self) -> None:
|
||||
"""Handle click event."""
|
||||
|
||||
@abstractmethod
|
||||
def on_hover(self) -> None:
|
||||
"""Handle hover event."""
|
||||
@ -4,12 +4,12 @@ import pygame
|
||||
from utils import CONFIG, Figure, GameMode
|
||||
|
||||
from game.log import log
|
||||
from game.sprites.tetromino import Tetromino
|
||||
|
||||
from .base import BaseScreen
|
||||
from .preview import Preview
|
||||
from .score import Score
|
||||
from .tetris import Tetris
|
||||
from .tetromino import Tetromino
|
||||
|
||||
|
||||
class Game(BaseScreen):
|
||||
@ -27,26 +27,20 @@ class Game(BaseScreen):
|
||||
music: Pygame music that plays in the background.
|
||||
"""
|
||||
|
||||
def __init__(self, mode: GameMode) -> None:
|
||||
log.info("Initializing the game")
|
||||
self.game_mode = mode
|
||||
self._initialize_pygeme()
|
||||
def __init__(self) -> None:
|
||||
self._initialize_game_components()
|
||||
self._start_background_music()
|
||||
|
||||
def draw(self) -> None:
|
||||
"""Update the display."""
|
||||
pygame.display.update()
|
||||
|
||||
def update(self) -> None:
|
||||
pass
|
||||
|
||||
def run(self) -> None:
|
||||
"""Run the main game loop."""
|
||||
while True:
|
||||
self.run_game_loop()
|
||||
|
||||
def run_game_loop(self) -> None:
|
||||
"""Run a single iteration of the game loop."""
|
||||
self.draw()
|
||||
self.handle_events()
|
||||
self.handle_events() # FIX:
|
||||
|
||||
self.tetris.run()
|
||||
self.score.run()
|
||||
@ -56,33 +50,20 @@ class Game(BaseScreen):
|
||||
self.draw()
|
||||
self.clock.tick(CONFIG.fps)
|
||||
|
||||
def handle_events(self) -> None:
|
||||
"""Handle Pygame events."""
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
self.exit()
|
||||
elif event.type == pygame.KEYDOWN:
|
||||
if event.key == pygame.K_q:
|
||||
self.exit()
|
||||
|
||||
def exit(self) -> None:
|
||||
"""Exit the game."""
|
||||
pygame.quit()
|
||||
sys.exit()
|
||||
def mute(self) -> None:
|
||||
"""Mute the game."""
|
||||
self.music.set_volume(0)
|
||||
self.tetris.mute()
|
||||
|
||||
def _initialize_game_components(self) -> None:
|
||||
"""Initialize game-related components."""
|
||||
self.clock = pygame.time.Clock()
|
||||
self.next_figure: Figure = self._generate_next_figure()
|
||||
|
||||
self.tetris = Tetris(self._get_next_figure, self._update_score)
|
||||
self.score = Score()
|
||||
self.preview = Preview()
|
||||
|
||||
def mute(self) -> None:
|
||||
"""Mute the game."""
|
||||
self.music.set_volume(0)
|
||||
self.tetris.mute()
|
||||
|
||||
def _update_score(self, lines: int, score: int, level: int) -> None:
|
||||
"""
|
||||
Update the game score.
|
||||
@ -114,14 +95,6 @@ class Game(BaseScreen):
|
||||
self.next_figure = self._generate_next_figure()
|
||||
return next_figure
|
||||
|
||||
def _initialize_pygeme(self) -> None:
|
||||
"""Initialize Pygame and set up the display."""
|
||||
pygame.init()
|
||||
pygame.display.set_caption(CONFIG.window.title)
|
||||
self.display_surface = pygame.display.set_mode(CONFIG.window.size)
|
||||
self.display_surface.fill(CONFIG.colors.bg)
|
||||
self.clock = pygame.time.Clock()
|
||||
|
||||
def _start_background_music(self) -> None:
|
||||
"""Start playing background music."""
|
||||
self.music = pygame.mixer.Sound(CONFIG.music.background)
|
||||
|
||||
116
src/game/screens/main.py
Normal file
116
src/game/screens/main.py
Normal file
@ -0,0 +1,116 @@
|
||||
import sys
|
||||
|
||||
import pygame
|
||||
from utils import CONFIG, GameMode
|
||||
|
||||
from game.log import log
|
||||
|
||||
from .base import BaseScreen, SceenElement, TextScreen
|
||||
from .game import Game
|
||||
from .menu_button import MenuButton
|
||||
|
||||
|
||||
class Main(BaseScreen, SceenElement, TextScreen):
|
||||
def __init__(self, mode: GameMode) -> None:
|
||||
log.info("Initializing the game")
|
||||
self._initialize_pygame()
|
||||
self._initialize_surface()
|
||||
self._initialize_rect()
|
||||
self._initialize_font()
|
||||
self._set_buttons()
|
||||
self._initialize_increment_height()
|
||||
self.game_mode = mode # TODO: use this
|
||||
|
||||
def draw(self) -> None:
|
||||
"""Update the display."""
|
||||
self._draw_background()
|
||||
self._draw_text()
|
||||
self._draw_border()
|
||||
pygame.display.update()
|
||||
|
||||
def update(self) -> None:
|
||||
pass
|
||||
|
||||
def handle_events(self) -> None:
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
self.exit()
|
||||
elif event.type == pygame.KEYDOWN:
|
||||
if event.key == pygame.K_q:
|
||||
self.exit()
|
||||
|
||||
def run(self) -> None:
|
||||
while True:
|
||||
self.draw()
|
||||
self.handle_events()
|
||||
|
||||
def exit(self) -> None:
|
||||
"""Exit the game."""
|
||||
pygame.quit()
|
||||
sys.exit()
|
||||
|
||||
def _set_buttons(self) -> None:
|
||||
self.buttons: list[MenuButton] = [
|
||||
MenuButton("Play", None),
|
||||
MenuButton("AI", None),
|
||||
MenuButton("Settings", None),
|
||||
MenuButton("Quit", self.exit),
|
||||
]
|
||||
|
||||
def _initialize_pygame(self) -> None:
|
||||
"""Initialize Pygame and set up the display."""
|
||||
pygame.init()
|
||||
pygame.display.set_caption(CONFIG.window.title)
|
||||
|
||||
def _draw_background(self) -> None:
|
||||
self.display_surface.fill(CONFIG.colors.bg)
|
||||
|
||||
def _draw_border(self) -> None:
|
||||
pass
|
||||
|
||||
def _initialize_surface(self) -> None:
|
||||
self.display_surface = pygame.display.set_mode(CONFIG.window.size)
|
||||
|
||||
def _initialize_rect(self) -> None:
|
||||
"""Initialize the rectangle."""
|
||||
self.rect = self.display_surface.get_rect(topright=(0, 0))
|
||||
|
||||
def _update_display_surface(self) -> None:
|
||||
"""Do nothing. Not needed in this class."""
|
||||
|
||||
def _initialize_increment_height(self) -> None:
|
||||
"""Initialize the increment height for positioning text elements/buttons."""
|
||||
self.increment_height = (
|
||||
self.display_surface.get_height() - CONFIG.window.size.height / 2
|
||||
) / len(self.buttons)
|
||||
|
||||
def _display_text(self, text: str, pos: tuple[float, float]) -> None:
|
||||
"""
|
||||
Display a single text element on the score surface.
|
||||
|
||||
Args:
|
||||
text: A tuple containing the label and value of the text element.
|
||||
pos: The position (x, y) where the text should be displayed.
|
||||
"""
|
||||
text_surface = self.font.render(text, True, CONFIG.colors.fg)
|
||||
text_rect = text_surface.get_rect(center=pos)
|
||||
self.display_surface.blit(text_surface, text_rect)
|
||||
|
||||
def _initialize_font(self) -> None:
|
||||
"""Initialize the font used to display the score."""
|
||||
self.font = pygame.font.Font(CONFIG.font.family, CONFIG.font.size)
|
||||
|
||||
def _draw_text(self) -> None:
|
||||
"""Draw the text and buttons on the surface."""
|
||||
|
||||
x, y = self.display_surface.get_width() / 2, 100
|
||||
self._display_text("Tetris", (x, y))
|
||||
|
||||
for idx, button in enumerate(self.buttons):
|
||||
x = self.display_surface.get_width() / 2
|
||||
y = (
|
||||
self.increment_height / 4
|
||||
+ idx * self.increment_height
|
||||
+ CONFIG.window.size.height / 4
|
||||
) # TODO: tweak a bit more
|
||||
button.draw(self.display_surface, (x, y))
|
||||
@ -1,7 +0,0 @@
|
||||
from game.log import log
|
||||
|
||||
from .base import BaseScreen
|
||||
|
||||
|
||||
class Menu(BaseScreen):
|
||||
pass
|
||||
88
src/game/screens/menu_button.py
Normal file
88
src/game/screens/menu_button.py
Normal file
@ -0,0 +1,88 @@
|
||||
from typing import Callable, Optional
|
||||
|
||||
import pygame
|
||||
from utils import CONFIG
|
||||
|
||||
from .base import BaseScreen, SceenElement, TextScreen
|
||||
from .button import Button
|
||||
|
||||
|
||||
class MenuButton(Button, BaseScreen, SceenElement, TextScreen):
|
||||
def __init__(self, text: str, action: Optional[Callable[[], None]]) -> None:
|
||||
super().__init__(text, action)
|
||||
self._initialize_surface()
|
||||
self._initialize_font()
|
||||
|
||||
def on_click(self) -> None:
|
||||
"""Handle click event."""
|
||||
if self.action:
|
||||
self.action()
|
||||
|
||||
def on_hover(self) -> None:
|
||||
"""Handle hover event."""
|
||||
self._draw_border()
|
||||
|
||||
def run(self) -> None:
|
||||
"""Display the button on the game surface."""
|
||||
self.draw()
|
||||
|
||||
def update(self) -> None:
|
||||
"""Update the button."""
|
||||
pass
|
||||
|
||||
def draw(self, surface: pygame.Surface, pos: tuple[float, float]) -> None:
|
||||
"""Draw the button on the button surface."""
|
||||
self._initialize_rect(pos)
|
||||
self._update_display_surface()
|
||||
self._draw_background()
|
||||
self._draw_text()
|
||||
self._draw_border()
|
||||
|
||||
def _initialize_surface(self) -> None:
|
||||
"""Initialize the button surface."""
|
||||
self.surface = pygame.Surface(CONFIG.window.button.size)
|
||||
self.display_surface = pygame.display.get_surface()
|
||||
|
||||
def _initialize_rect(self, pos: tuple[float, float]) -> None:
|
||||
"""Initialize the button rectangle."""
|
||||
self.rect = self.surface.get_rect(center=pos)
|
||||
|
||||
def _draw_text(self) -> None:
|
||||
"""Draw the text on the text surface."""
|
||||
x = self.surface.get_width() / 2
|
||||
y = self.surface.get_height() / 2
|
||||
self._display_text(self.text, (x, y))
|
||||
|
||||
def _display_text(self, text: str, pos: tuple[float, float]) -> None:
|
||||
"""
|
||||
Display a single text element on the button surface.
|
||||
|
||||
Args:
|
||||
text: The text to be displayed.
|
||||
pos: The position (x, y) where the text should be displayed.
|
||||
"""
|
||||
text_surface = self.font.render(text, True, CONFIG.colors.fg_sidebar)
|
||||
text_rect = text_surface.get_rect(center=pos)
|
||||
self.surface.blit(text_surface, text_rect)
|
||||
|
||||
def _initialize_font(self) -> None:
|
||||
"""Initialize the font used to display the score."""
|
||||
self.font = pygame.font.Font(CONFIG.font.family, CONFIG.font.size)
|
||||
|
||||
def _draw_background(self) -> None:
|
||||
"""Fill the background of the button."""
|
||||
self.surface.fill(CONFIG.colors.bg_sidebar)
|
||||
|
||||
def _draw_border(self) -> None:
|
||||
"""Draw the border of the button."""
|
||||
pygame.draw.rect(
|
||||
self.display_surface,
|
||||
CONFIG.colors.border_highlight,
|
||||
self.rect,
|
||||
CONFIG.game.line_width * 2,
|
||||
CONFIG.game.border_radius,
|
||||
)
|
||||
|
||||
def _update_display_surface(self) -> None:
|
||||
"""Update the display surface."""
|
||||
self.display_surface.blit(self.surface, self.rect)
|
||||
@ -11,7 +11,7 @@ class Preview(BaseScreen, SceenElement):
|
||||
Attributes:
|
||||
surface: Pygame surface representing the preview.
|
||||
rect: Pygame rectangle representing the preview.
|
||||
dispaly_surface: Pygame display surface.
|
||||
display_surface: Pygame display surface.
|
||||
increment_height: Height of each figure in the preview.
|
||||
"""
|
||||
|
||||
@ -34,7 +34,7 @@ class Preview(BaseScreen, SceenElement):
|
||||
|
||||
def draw(self) -> None:
|
||||
"""Draw the preview on the preview surface."""
|
||||
self._update_diplaysurface()
|
||||
self._update_display_surface()
|
||||
self._draw_background()
|
||||
self._draw_border()
|
||||
self._draw_figure()
|
||||
@ -42,7 +42,7 @@ class Preview(BaseScreen, SceenElement):
|
||||
def _draw_border(self) -> None:
|
||||
"""Draw the border around the preview surface."""
|
||||
pygame.draw.rect(
|
||||
self.dispaly_surface,
|
||||
self.display_surface,
|
||||
CONFIG.colors.border_highlight,
|
||||
self.rect,
|
||||
CONFIG.game.line_width * 2,
|
||||
@ -70,7 +70,7 @@ class Preview(BaseScreen, SceenElement):
|
||||
def _initialize_surface(self) -> None:
|
||||
"""Initialize the preview surface."""
|
||||
self.surface = pygame.Surface(CONFIG.sidebar.preview)
|
||||
self.dispaly_surface = pygame.display.get_surface()
|
||||
self.display_surface = pygame.display.get_surface()
|
||||
|
||||
def _initialize_rect(self) -> None:
|
||||
"""Initialize the preview rectangle."""
|
||||
@ -81,6 +81,6 @@ class Preview(BaseScreen, SceenElement):
|
||||
)
|
||||
)
|
||||
|
||||
def _update_diplaysurface(self) -> None:
|
||||
def _update_display_surface(self) -> None:
|
||||
"""Update the display surface."""
|
||||
self.dispaly_surface.blit(self.surface, self.rect)
|
||||
self.display_surface.blit(self.surface, self.rect)
|
||||
|
||||
@ -10,7 +10,7 @@ class Score(BaseScreen, SceenElement, TextScreen):
|
||||
|
||||
Attributes:
|
||||
surface: Pygame surface representing the score.
|
||||
dispaly_surface: Pygame display surface.
|
||||
display_surface: Pygame display surface.
|
||||
rect: Pygame rectangle representing the score.
|
||||
font: Pygame font used to display the score.
|
||||
text: Text to be displayed on the score.
|
||||
@ -26,7 +26,6 @@ class Score(BaseScreen, SceenElement, TextScreen):
|
||||
|
||||
def run(self) -> None:
|
||||
"""Display the score on the game surface."""
|
||||
self._update_diplaysurface()
|
||||
self.draw()
|
||||
|
||||
def update(self, lines: int, score: int, level: int) -> None:
|
||||
@ -46,6 +45,7 @@ class Score(BaseScreen, SceenElement, TextScreen):
|
||||
|
||||
def draw(self) -> None:
|
||||
"""Draw the score on the score surface."""
|
||||
self._update_display_surface()
|
||||
self._draw_background()
|
||||
self._draw_text()
|
||||
self._draw_border()
|
||||
@ -62,8 +62,8 @@ class Score(BaseScreen, SceenElement, TextScreen):
|
||||
Display a single text element on the score surface.
|
||||
|
||||
Args:
|
||||
text (tuple[str, int]): A tuple containing the label and value of the text element.
|
||||
pos (tuple[int, int]): The position (x, y) where the text should be displayed.
|
||||
text: A tuple containing the label and value of the text element.
|
||||
pos: The position (x, y) where the text should be displayed.
|
||||
"""
|
||||
text_surface = self.font.render(
|
||||
f"{text[0]}: {text[1]}", True, CONFIG.colors.fg_sidebar
|
||||
@ -74,7 +74,7 @@ class Score(BaseScreen, SceenElement, TextScreen):
|
||||
def _draw_border(self) -> None:
|
||||
"""Draw the border of the score surface."""
|
||||
pygame.draw.rect(
|
||||
self.dispaly_surface,
|
||||
self.display_surface,
|
||||
CONFIG.colors.border_highlight,
|
||||
self.rect,
|
||||
CONFIG.game.line_width * 2,
|
||||
@ -88,12 +88,12 @@ class Score(BaseScreen, SceenElement, TextScreen):
|
||||
def _initialize_surface(self) -> None:
|
||||
"""Initialize the score surface."""
|
||||
self.surface = pygame.Surface(CONFIG.sidebar.score)
|
||||
self.dispaly_surface = pygame.display.get_surface()
|
||||
self.display_surface = pygame.display.get_surface()
|
||||
|
||||
def _initialize_rect(self) -> None:
|
||||
"""Initialize the score rectangle."""
|
||||
self.rect = self.surface.get_rect(
|
||||
bottomright=CONFIG.window.size.sub(CONFIG.window.padding)
|
||||
bottomright=CONFIG.window.size - CONFIG.window.padding
|
||||
)
|
||||
|
||||
def _initialize_font(self) -> None:
|
||||
@ -104,6 +104,6 @@ class Score(BaseScreen, SceenElement, TextScreen):
|
||||
"""Initialize the increment height for positioning text elements."""
|
||||
self.increment_height = self.surface.get_height() / 3
|
||||
|
||||
def _update_diplaysurface(self) -> None:
|
||||
def _update_display_surface(self) -> None:
|
||||
"""Update the display surface."""
|
||||
self.dispaly_surface.blit(self.surface, self.rect)
|
||||
self.display_surface.blit(self.surface, self.rect)
|
||||
|
||||
@ -9,7 +9,7 @@ from game.sprites.block import Block
|
||||
from game.sprites.tetromino import Tetromino
|
||||
from game.timer import Timer, Timers
|
||||
|
||||
from .base import BaseScreen
|
||||
from .base import BaseScreen, SceenElement
|
||||
|
||||
|
||||
class Tetris(BaseScreen):
|
||||
@ -46,7 +46,7 @@ class Tetris(BaseScreen):
|
||||
get_next_figure: Callable[[], Figure],
|
||||
update_score: Callable[[int, int, int], None],
|
||||
) -> None:
|
||||
self._initialize_game_surface()
|
||||
self._initialize_surface()
|
||||
self._initialize_sprites()
|
||||
|
||||
self.get_next_figure = get_next_figure
|
||||
@ -70,7 +70,7 @@ class Tetris(BaseScreen):
|
||||
def draw(self) -> None:
|
||||
"""Draw the game surface and its components."""
|
||||
self.update()
|
||||
self._fill_game_surface()
|
||||
self._draw_background()
|
||||
self.sprites.draw(self.surface)
|
||||
self._draw_border()
|
||||
self._draw_grid()
|
||||
@ -249,10 +249,13 @@ class Tetris(BaseScreen):
|
||||
self._draw_border()
|
||||
self._draw_grid()
|
||||
|
||||
def _initialize_game_surface(self) -> None:
|
||||
def _initialize_surface(self) -> None:
|
||||
"""Initialize the game surface."""
|
||||
self.surface = pygame.Surface(CONFIG.game.size)
|
||||
self.dispaly_surface = pygame.display.get_surface()
|
||||
|
||||
def _initialize_rect(self) -> None:
|
||||
"""Initialize the rectangle."""
|
||||
self.rect = self.surface.get_rect(topleft=CONFIG.game.pos)
|
||||
|
||||
def _initialize_sprites(self) -> None:
|
||||
@ -308,7 +311,7 @@ class Tetris(BaseScreen):
|
||||
"""Update the display surface."""
|
||||
self.dispaly_surface.blit(self.surface, CONFIG.game.pos)
|
||||
|
||||
def _fill_game_surface(self) -> None:
|
||||
def _draw_background(self) -> None:
|
||||
"""Fill the game surface with background color."""
|
||||
self.surface.fill(CONFIG.colors.bg_float)
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@ from typing import Any
|
||||
|
||||
import numpy as np
|
||||
import pygame
|
||||
from utils import CONFIG, Rotation, Size
|
||||
from utils import CONFIG, Field, Rotation, Size
|
||||
|
||||
|
||||
class Block(pygame.sprite.Sprite):
|
||||
@ -24,7 +24,7 @@ class Block(pygame.sprite.Sprite):
|
||||
self,
|
||||
/,
|
||||
*,
|
||||
group: pygame.sprite.Group[Any],
|
||||
group: pygame.sprite.Group,
|
||||
pos: pygame.Vector2,
|
||||
color: str,
|
||||
) -> None:
|
||||
@ -40,7 +40,7 @@ class Block(pygame.sprite.Sprite):
|
||||
self.pos.y * CONFIG.game.cell.width,
|
||||
)
|
||||
|
||||
def vertical_collision(self, x: int, field: np.ndarray[int, Any]) -> bool:
|
||||
def vertical_collision(self, x: int, field: np.ndarray[Field, Any]) -> bool:
|
||||
"""
|
||||
Checks for vertical collision with the game field.
|
||||
|
||||
@ -53,7 +53,7 @@ class Block(pygame.sprite.Sprite):
|
||||
"""
|
||||
return not 0 <= x < CONFIG.game.columns or field[int(self.pos.y), x]
|
||||
|
||||
def horizontal_collision(self, y: int, field: np.ndarray[int, Any]) -> bool:
|
||||
def horizontal_collision(self, y: int, field: np.ndarray[Field, Any]) -> bool:
|
||||
"""
|
||||
Checks for horizontal collision with the game field.
|
||||
|
||||
|
||||
@ -2,10 +2,11 @@ from typing import Any, Callable, Optional
|
||||
|
||||
import numpy as np
|
||||
import pygame
|
||||
from utils import CONFIG, Direction, Figure, Rotation, Size
|
||||
from utils import CONFIG, Direction, Field, Figure, Rotation, Size
|
||||
|
||||
from game.log import log
|
||||
|
||||
from .block import Block
|
||||
from .log import log
|
||||
|
||||
|
||||
class Tetromino:
|
||||
@ -29,9 +30,9 @@ class Tetromino:
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
group: pygame.sprite.Group[Any],
|
||||
group: pygame.sprite.Group,
|
||||
create_new: Callable[[], None],
|
||||
field: np.ndarray[int, Any],
|
||||
field: np.ndarray[Field, Any],
|
||||
shape: Optional[Figure] = None,
|
||||
) -> None:
|
||||
self.figure: Figure = self._generate_figure(shape)
|
||||
@ -156,7 +157,7 @@ class Tetromino:
|
||||
for pos in new_positions
|
||||
)
|
||||
|
||||
def _initialize_blocks(self, group: pygame.sprite.Group[Any]) -> list[Block]:
|
||||
def _initialize_blocks(self, group: pygame.sprite.Group) -> list[Block]:
|
||||
"""
|
||||
Initializes Tetromino blocks.
|
||||
|
||||
|
||||
@ -41,6 +41,11 @@ class Font:
|
||||
size: int = 32
|
||||
|
||||
|
||||
@define
|
||||
class Button:
|
||||
size: Size = Size(200, 50)
|
||||
|
||||
|
||||
@define
|
||||
class Window:
|
||||
title: str = "Tetris"
|
||||
@ -49,6 +54,7 @@ class Window:
|
||||
Game().size.width + SideBar().size.width + padding * 3,
|
||||
Game().size.height + padding * 2,
|
||||
)
|
||||
button: Button = Button()
|
||||
|
||||
|
||||
@define
|
||||
|
||||
@ -5,12 +5,7 @@ class Size(NamedTuple):
|
||||
width: int | float
|
||||
height: int | float
|
||||
|
||||
def add(self, other: Union["Size", int, float]) -> "Size":
|
||||
if isinstance(other, Size):
|
||||
return Size(self.width + other.width, self.height + other.height)
|
||||
return Size(self.width + other, self.height + other)
|
||||
|
||||
def sub(self, other: Union["Size", int, float]) -> "Size":
|
||||
def __sub__(self, other: Union["Size", int, float]) -> "Size":
|
||||
if isinstance(other, Size):
|
||||
return Size(self.width - other.width, self.height - other.height)
|
||||
return Size(self.width - other, self.height - other)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user