mirror of
https://github.com/kristoferssolo/2048.git
synced 2025-10-21 15:20:35 +00:00
feat(game): set Menu as primary screen
This commit is contained in:
parent
d22b5dbab2
commit
f95ca3aaf6
4
main.py
4
main.py
@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
|
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
from py2048 import Game
|
from py2048 import Menu
|
||||||
|
|
||||||
|
|
||||||
@logger.catch
|
@logger.catch
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
Game().run()
|
Menu().run()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
from .config import Config
|
from .config import Config
|
||||||
from .game import Game
|
from .screens import Menu
|
||||||
|
|
||||||
__all__ = ["Config", "Game"]
|
__all__ = ["Config", "Menu"]
|
||||||
|
|||||||
@ -1,76 +0,0 @@
|
|||||||
import sys
|
|
||||||
|
|
||||||
import pygame
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from .config import Config
|
|
||||||
from .objects import Board
|
|
||||||
from .screens import Header, Menu
|
|
||||||
from .utils import Direction, setup_logger
|
|
||||||
|
|
||||||
|
|
||||||
class Game:
|
|
||||||
def __init__(self) -> None:
|
|
||||||
setup_logger()
|
|
||||||
logger.info("Initializing game")
|
|
||||||
|
|
||||||
pygame.init()
|
|
||||||
self.screen: pygame.Surface = pygame.display.set_mode(Config.SCREEN.size)
|
|
||||||
pygame.display.set_caption("2048")
|
|
||||||
self.board = Board()
|
|
||||||
self.header = Header()
|
|
||||||
self.menu = Menu()
|
|
||||||
|
|
||||||
def run(self) -> None:
|
|
||||||
"""Run the game loop."""
|
|
||||||
while True:
|
|
||||||
self._hande_events()
|
|
||||||
self._update()
|
|
||||||
self._render()
|
|
||||||
|
|
||||||
def _update(self) -> None:
|
|
||||||
"""Update the game."""
|
|
||||||
self.board.update()
|
|
||||||
|
|
||||||
def _render(self) -> None:
|
|
||||||
"""Render the game."""
|
|
||||||
self.screen.fill(Config.COLORSCHEME.BG)
|
|
||||||
# self.board.draw(self.screen)
|
|
||||||
# self.header.draw(self.screen, 2048)
|
|
||||||
self.menu.draw(self.screen)
|
|
||||||
pygame.display.flip()
|
|
||||||
|
|
||||||
def _hande_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 in (pygame.K_LEFT, pygame.K_a, pygame.K_h):
|
|
||||||
self.move_left()
|
|
||||||
elif event.key in (pygame.K_RIGHT, pygame.K_d, pygame.K_l):
|
|
||||||
self.move_right()
|
|
||||||
elif event.key in (pygame.K_UP, pygame.K_w, pygame.K_k):
|
|
||||||
self.move_up()
|
|
||||||
elif event.key in (pygame.K_DOWN, pygame.K_s, pygame.K_j):
|
|
||||||
self.move_down()
|
|
||||||
elif event.key == pygame.K_q:
|
|
||||||
self.exit()
|
|
||||||
self.menu._handle_events(event)
|
|
||||||
|
|
||||||
def move_up(self) -> None:
|
|
||||||
self.board.move(Direction.UP)
|
|
||||||
|
|
||||||
def move_down(self) -> None:
|
|
||||||
self.board.move(Direction.DOWN)
|
|
||||||
|
|
||||||
def move_left(self) -> None:
|
|
||||||
self.board.move(Direction.LEFT)
|
|
||||||
|
|
||||||
def move_right(self) -> None:
|
|
||||||
self.board.move(Direction.RIGHT)
|
|
||||||
|
|
||||||
def exit(self) -> None:
|
|
||||||
"""Exit the game."""
|
|
||||||
pygame.quit()
|
|
||||||
sys.exit()
|
|
||||||
@ -18,7 +18,7 @@ class UIElement(ABC, metaclass=ABCMeta):
|
|||||||
font_color: str,
|
font_color: str,
|
||||||
font_size: int = Config.FONT.size,
|
font_size: int = Config.FONT.size,
|
||||||
font_family: str = Config.FONT.family,
|
font_family: str = Config.FONT.family,
|
||||||
size: Size = Size(50, 50),
|
size: Optional[Size] = Size(50, 50),
|
||||||
text: str = "",
|
text: str = "",
|
||||||
border_radius: int = 0,
|
border_radius: int = 0,
|
||||||
border_width: int = 0,
|
border_width: int = 0,
|
||||||
|
|||||||
@ -42,6 +42,7 @@ class Button(ClickableUIElement, pygame.sprite.Sprite):
|
|||||||
|
|
||||||
def _draw_background(self, surface: pygame.Surface) -> None:
|
def _draw_background(self, surface: pygame.Surface) -> None:
|
||||||
"""Draw a rectangle on the given surface."""
|
"""Draw a rectangle on the given surface."""
|
||||||
|
if self.size:
|
||||||
pygame.draw.rect(
|
pygame.draw.rect(
|
||||||
surface,
|
surface,
|
||||||
self.bg_color,
|
self.bg_color,
|
||||||
|
|||||||
@ -7,13 +7,15 @@ from py2048.utils import Position, Size
|
|||||||
from .abc import UIElement
|
from .abc import UIElement
|
||||||
|
|
||||||
|
|
||||||
class Label(UIElement):
|
class Label(UIElement, pygame.sprite.Sprite):
|
||||||
def __init__(self, *args, **kwargs) -> None:
|
def __init__(self, *args, **kwargs) -> None:
|
||||||
|
pygame.sprite.Sprite.__init__(self)
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
self.image = self._create_surface()
|
self.image = self._create_surface()
|
||||||
self.rect = self.image.get_rect()
|
self.rect = self.image.get_rect()
|
||||||
self.rect.topleft = self.position
|
self.rect.topleft = self.position
|
||||||
|
self.update()
|
||||||
|
|
||||||
def draw(self, surface: pygame.Surface) -> None:
|
def draw(self, surface: pygame.Surface) -> None:
|
||||||
"""Draw the element on the given surface."""
|
"""Draw the element on the given surface."""
|
||||||
@ -29,23 +31,17 @@ class Label(UIElement):
|
|||||||
|
|
||||||
def _draw_background(self, surface: pygame.Surface) -> None:
|
def _draw_background(self, surface: pygame.Surface) -> None:
|
||||||
"""Draw a background for the given surface."""
|
"""Draw a background for the given surface."""
|
||||||
rect = (0, 0, *self.size)
|
if self.size:
|
||||||
pygame.draw.rect(
|
|
||||||
surface, self.bg_color, rect, border_radius=Config.TILE.border.radius
|
|
||||||
) # background
|
|
||||||
pygame.draw.rect(
|
pygame.draw.rect(
|
||||||
surface,
|
surface,
|
||||||
(0, 0, 0, 0),
|
self.bg_color,
|
||||||
rect,
|
(0, 0, *self.size),
|
||||||
border_radius=Config.TILE.border.radius,
|
border_radius=Config.TILE.border.radius,
|
||||||
width=Config.TILE.border.width,
|
)
|
||||||
) # border
|
|
||||||
|
|
||||||
def _draw_text(self) -> None:
|
def _draw_text(self) -> None:
|
||||||
"""Draw the text of the element."""
|
"""Draw the text of the element."""
|
||||||
self.rendered_text = self.font.render(
|
self.rendered_text = self.font.render(self.text, True, self.font_color)
|
||||||
self.text, True, self.font_color, self.bg_color
|
|
||||||
)
|
|
||||||
self.image.blit(
|
self.image.blit(
|
||||||
self.rendered_text,
|
self.rendered_text,
|
||||||
self.rendered_text.get_rect(center=self.image.get_rect().center),
|
self.rendered_text.get_rect(center=self.image.get_rect().center),
|
||||||
|
|||||||
@ -39,6 +39,7 @@ class Tile(MovableUIElement, pygame.sprite.Sprite):
|
|||||||
self.image = self._create_surface()
|
self.image = self._create_surface()
|
||||||
self.rect = self.image.get_rect()
|
self.rect = self.image.get_rect()
|
||||||
self.rect.topleft = self.position
|
self.rect.topleft = self.position
|
||||||
|
self.update()
|
||||||
|
|
||||||
def draw(self, surface: pygame.Surface) -> None:
|
def draw(self, surface: pygame.Surface) -> None:
|
||||||
"""Draw the value of the tile."""
|
"""Draw the value of the tile."""
|
||||||
@ -55,6 +56,7 @@ class Tile(MovableUIElement, pygame.sprite.Sprite):
|
|||||||
|
|
||||||
def _draw_background(self, surface: pygame.Surface) -> None:
|
def _draw_background(self, surface: pygame.Surface) -> None:
|
||||||
"""Draw a rounded rectangle on the given surface."""
|
"""Draw a rounded rectangle on the given surface."""
|
||||||
|
if self.size:
|
||||||
pygame.draw.rect(
|
pygame.draw.rect(
|
||||||
surface,
|
surface,
|
||||||
self._get_color(),
|
self._get_color(),
|
||||||
@ -65,6 +67,7 @@ class Tile(MovableUIElement, pygame.sprite.Sprite):
|
|||||||
|
|
||||||
def _draw_border(self, surface: pygame.Surface) -> None:
|
def _draw_border(self, surface: pygame.Surface) -> None:
|
||||||
"""Draw a rounded border on the given surface."""
|
"""Draw a rounded border on the given surface."""
|
||||||
|
if self.size:
|
||||||
pygame.draw.rect(
|
pygame.draw.rect(
|
||||||
surface,
|
surface,
|
||||||
(0, 0, 0, 0),
|
(0, 0, 0, 0),
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
|
from .game import Game
|
||||||
from .header import Header
|
from .header import Header
|
||||||
from .menu import Menu
|
from .menu import Menu
|
||||||
|
|
||||||
__all__ = ["Header", "Menu"]
|
__all__ = ["Header", "Menu", "Game"]
|
||||||
|
|||||||
43
src/py2048/screens/game.py
Normal file
43
src/py2048/screens/game.py
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import pygame
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
|
from py2048 import Config
|
||||||
|
from py2048.objects import Board
|
||||||
|
from py2048.utils import Direction, setup_logger
|
||||||
|
|
||||||
|
from .header import Header
|
||||||
|
|
||||||
|
|
||||||
|
class Game:
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.header = Header()
|
||||||
|
self.board = Board()
|
||||||
|
|
||||||
|
def draw(self, surface: pygame.Surface) -> None:
|
||||||
|
surface.fill(Config.COLORSCHEME.BG)
|
||||||
|
self.board.draw(surface)
|
||||||
|
self.header.draw(surface, 2048)
|
||||||
|
pygame.display.flip()
|
||||||
|
|
||||||
|
def handle_events(self, event: pygame.Event) -> None:
|
||||||
|
if event.type == pygame.KEYDOWN:
|
||||||
|
if event.key in (pygame.K_LEFT, pygame.K_a, pygame.K_h):
|
||||||
|
self.move_left()
|
||||||
|
elif event.key in (pygame.K_RIGHT, pygame.K_d, pygame.K_l):
|
||||||
|
self.move_right()
|
||||||
|
elif event.key in (pygame.K_UP, pygame.K_w, pygame.K_k):
|
||||||
|
self.move_up()
|
||||||
|
elif event.key in (pygame.K_DOWN, pygame.K_s, pygame.K_j):
|
||||||
|
self.move_down()
|
||||||
|
|
||||||
|
def move_up(self) -> None:
|
||||||
|
self.board.move(Direction.UP)
|
||||||
|
|
||||||
|
def move_down(self) -> None:
|
||||||
|
self.board.move(Direction.DOWN)
|
||||||
|
|
||||||
|
def move_left(self) -> None:
|
||||||
|
self.board.move(Direction.LEFT)
|
||||||
|
|
||||||
|
def move_right(self) -> None:
|
||||||
|
self.board.move(Direction.RIGHT)
|
||||||
@ -8,20 +8,32 @@ from py2048.utils import Position, Size
|
|||||||
class Header:
|
class Header:
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.rect = pygame.Rect(0, 0, *Config.HEADER.size)
|
self.rect = pygame.Rect(0, 0, *Config.HEADER.size)
|
||||||
|
self.labels = self._create_labels()
|
||||||
|
|
||||||
def draw(self, screen: pygame.Surface, score: int) -> None:
|
def _create_labels(self) -> pygame.sprite.Group:
|
||||||
"""Draw the header."""
|
score = Label(
|
||||||
self.label = Label(
|
text=f"SCORE\n{0}",
|
||||||
text=f"{score}",
|
|
||||||
size=Size(50, 50),
|
size=Size(50, 50),
|
||||||
position=Position(0, 0),
|
position=Position(0, 0),
|
||||||
bg_color=Config.COLORSCHEME.BOARD_BG,
|
bg_color=Config.COLORSCHEME.BOARD_BG,
|
||||||
font_color=Config.COLORSCHEME.DARK_TEXT,
|
font_color=Config.COLORSCHEME.LIGHT_TEXT,
|
||||||
font_size=16,
|
font_size=16,
|
||||||
)
|
)
|
||||||
self.label.draw(screen)
|
highscore = Label(
|
||||||
|
text=f"HIGHSCORE\n{2048}",
|
||||||
|
size=Size(50, 50),
|
||||||
|
position=Position(200, 0),
|
||||||
|
bg_color=Config.COLORSCHEME.BOARD_BG,
|
||||||
|
font_color=Config.COLORSCHEME.LIGHT_TEXT,
|
||||||
|
font_size=16,
|
||||||
|
)
|
||||||
|
return pygame.sprite.Group(score, highscore)
|
||||||
|
|
||||||
|
def draw(self, screen: pygame.Surface, score: int) -> None:
|
||||||
|
"""Draw the header."""
|
||||||
|
self.labels.draw(screen)
|
||||||
|
|
||||||
def update(self, score: int) -> None:
|
def update(self, score: int) -> None:
|
||||||
"""Update the header."""
|
"""Update the header."""
|
||||||
self.label.text = f"SCORE\n{score}"
|
# self.labels. = f"SCORE\n{score}"
|
||||||
self.label.update()
|
self.labels.update()
|
||||||
|
|||||||
@ -1,52 +1,99 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
import pygame
|
import pygame
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
||||||
from py2048 import Config
|
from py2048 import Config
|
||||||
from py2048.objects import Button
|
from py2048.objects import Button
|
||||||
from py2048.utils import Position
|
from py2048.utils import Position, setup_logger
|
||||||
|
|
||||||
|
from .game import Game
|
||||||
|
|
||||||
|
|
||||||
class Menu(pygame.sprite.AbstractGroup):
|
class Menu:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
setup_logger()
|
||||||
|
pygame.init()
|
||||||
|
pygame.display.set_caption("2048")
|
||||||
|
self._surface: pygame.Surface = pygame.display.set_mode(Config.SCREEN.size)
|
||||||
|
|
||||||
buttons_data = {
|
logger.info("Initializing game")
|
||||||
|
|
||||||
|
self._buttons_data = {
|
||||||
"Play": self.play,
|
"Play": self.play,
|
||||||
"AI": self.ai,
|
"AI": self.ai,
|
||||||
"Settings": self.settings,
|
"Settings": self.settings,
|
||||||
"Exit": self.exit,
|
"Exit": self.exit,
|
||||||
}
|
}
|
||||||
button_width, button_height = 120, 50
|
self._game_active = False
|
||||||
|
self._ai_active = False
|
||||||
|
self._setting_active = False
|
||||||
|
self._buttons = self._create_buttons()
|
||||||
|
|
||||||
for index, (text, action) in enumerate(buttons_data.items(), start=1):
|
def _create_buttons(self) -> pygame.sprite.Group:
|
||||||
self.add(
|
"""Create the buttons."""
|
||||||
|
width, height = 120, 50
|
||||||
|
buttons = pygame.sprite.Group()
|
||||||
|
for index, (text, action) in enumerate(self._buttons_data.items(), start=1):
|
||||||
|
buttons.add(
|
||||||
Button(
|
Button(
|
||||||
position=Position(
|
position=(
|
||||||
Config.SCREEN.size.width / 2 - button_width / 2,
|
Config.SCREEN.size.width / 2 - width / 2,
|
||||||
Config.SCREEN.size.height / len(buttons_data) * index
|
Config.SCREEN.size.height / len(self._buttons_data) * index
|
||||||
- button_height,
|
- height,
|
||||||
),
|
),
|
||||||
bg_color=Config.COLORSCHEME.BOARD_BG,
|
bg_color=Config.COLORSCHEME.BOARD_BG,
|
||||||
font_color=Config.COLORSCHEME.LIGHT_TEXT,
|
font_color=Config.COLORSCHEME.LIGHT_TEXT,
|
||||||
hover_color=Config.COLORSCHEME.TILE_0,
|
hover_color=Config.COLORSCHEME.TILE_0,
|
||||||
size=(button_width, button_height),
|
size=(width, height),
|
||||||
text=text,
|
text=text,
|
||||||
border_radius=Config.TILE.border.radius,
|
border_radius=Config.TILE.border.radius,
|
||||||
action=action,
|
action=action,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
def _handle_events(self, event: pygame.event.Event) -> None:
|
return buttons
|
||||||
"""Handle the event."""
|
|
||||||
if event.type == pygame.MOUSEBUTTONDOWN:
|
def draw(self) -> None:
|
||||||
for button in self.sprites():
|
self._surface.fill(Config.COLORSCHEME.BG)
|
||||||
|
self._buttons.draw(self._surface)
|
||||||
|
pygame.display.flip()
|
||||||
|
|
||||||
|
def run(self) -> None:
|
||||||
|
"""Run the game loop."""
|
||||||
|
while True:
|
||||||
|
self._hande_events()
|
||||||
|
|
||||||
|
if self._game_active:
|
||||||
|
self.game.draw(self._surface)
|
||||||
|
elif self._ai_active:
|
||||||
|
pass
|
||||||
|
elif self._setting_active:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
self.draw()
|
||||||
|
|
||||||
|
def _hande_events(self) -> None:
|
||||||
|
"""Handle pygame events."""
|
||||||
|
for event in pygame.event.get():
|
||||||
|
if event.type == pygame.QUIT:
|
||||||
|
self.exit()
|
||||||
|
elif event.type == pygame.MOUSEBUTTONDOWN:
|
||||||
|
for button in self._buttons:
|
||||||
button.on_click(Position(*event.pos))
|
button.on_click(Position(*event.pos))
|
||||||
elif event.type == pygame.MOUSEMOTION:
|
elif event.type == pygame.MOUSEMOTION:
|
||||||
for button in self.sprites():
|
for button in self._buttons:
|
||||||
button.on_hover(Position(*event.pos))
|
button.on_hover(Position(*event.pos))
|
||||||
|
elif event.type == pygame.KEYDOWN:
|
||||||
|
if event.key == pygame.K_q:
|
||||||
|
self.exit()
|
||||||
|
if self._game_active:
|
||||||
|
self.game.handle_events(event)
|
||||||
|
|
||||||
def play(self) -> None:
|
def play(self) -> None:
|
||||||
logger.debug("Play")
|
logger.debug("Launching game")
|
||||||
|
self._game_active = True
|
||||||
|
self.game = Game()
|
||||||
|
|
||||||
def ai(self) -> None:
|
def ai(self) -> None:
|
||||||
logger.debug("AI")
|
logger.debug("AI")
|
||||||
@ -55,4 +102,7 @@ class Menu(pygame.sprite.AbstractGroup):
|
|||||||
logger.debug("Settings")
|
logger.debug("Settings")
|
||||||
|
|
||||||
def exit(self) -> None:
|
def exit(self) -> None:
|
||||||
logger.debug("Exit")
|
"""Exit the game."""
|
||||||
|
logger.debug("Exiting")
|
||||||
|
pygame.quit()
|
||||||
|
sys.exit()
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user