feat(game): add header and center board

This commit is contained in:
Kristofers Solo 2024-01-01 21:17:36 +02:00
parent 70e0172ec7
commit e7932303c2
5 changed files with 73 additions and 30 deletions

View File

@ -61,10 +61,11 @@ class Block(pygame.sprite.Sprite):
def _is_out_if_bounds(self, x: int, y: int) -> bool: def _is_out_if_bounds(self, x: int, y: int) -> bool:
"""Return whether the block is out of bounds.""" """Return whether the block is out of bounds."""
return not ( board_left = Config.BOARD_X
0 <= x <= Config.GRID_WIDTH - Config.BLOCK_SIZE board_right = Config.BOARD_X + Config.BOARD_WIDTH - Config.BLOCK_SIZE
and 0 <= y <= Config.GRID_HEIGHT - Config.BLOCK_SIZE board_top = Config.BOARD_Y
) board_bottom = Config.BOARD_Y + Config.BOARD_HEIGHT - Config.BLOCK_SIZE
return not (board_left <= x <= board_right and board_top <= y <= board_bottom)
def _has_collision(self, x: int, y: int) -> bool: def _has_collision(self, x: int, y: int) -> bool:
"""Checks whether the block has a collision with any other block.""" """Checks whether the block has a collision with any other block."""

View File

@ -10,12 +10,26 @@ from .utils import Direction
class Board(pygame.sprite.Group): class Board(pygame.sprite.Group):
def __init__(self, screen: pygame.Surface): def __init__(self):
super().__init__() super().__init__()
self.screen = screen self.rect = pygame.Rect(0, 0, Config.BOARD_WIDTH, Config.BOARD_HEIGHT)
self.rect.x = Config.BOARD_X
self.rect.y = Config.BOARD_Y
self.initiate_game()
def initiate_game(self) -> None:
"""Initiate the game."""
self.generate_initial_blocks() self.generate_initial_blocks()
def draw(self, screen: pygame.Surface) -> None:
"""Draw the board."""
block: Block
pygame.draw.rect(screen, Color.YELLOW, self.rect, 2)
super().draw(screen)
def move(self, direction: Direction): def move(self, direction: Direction):
"""Move the blocks in the specified direction."""
blocks = self.sprites() blocks = self.sprites()
block: Block block: Block
@ -54,8 +68,8 @@ class Board(pygame.sprite.Group):
"""Generate a block with random coordinates aligned with the grid.""" """Generate a block with random coordinates aligned with the grid."""
while True: while True:
# Generate random coordinates aligned with the grid # Generate random coordinates aligned with the grid
x = random.randint(0, 3) * Config.BLOCK_SIZE x = random.randint(0, 3) * Config.BLOCK_SIZE + Config.BOARD_X
y = random.randint(0, 3) * Config.BLOCK_SIZE y = random.randint(0, 3) * Config.BLOCK_SIZE + Config.BOARD_Y
block = Block(x, y, self) block = Block(x, y, self)
colliding_blocks = pygame.sprite.spritecollide( colliding_blocks = pygame.sprite.spritecollide(
@ -64,12 +78,11 @@ class Board(pygame.sprite.Group):
if not colliding_blocks: if not colliding_blocks:
self.add(block) self.add(block)
logger.debug(f"Created block at {block.pos}") return
break
def _is_full(self) -> bool: def _is_full(self) -> bool:
"""Check if the board is full.""" """Check if the board is full."""
return len(self.sprites()) == Config.GRID_SIZE**2 return len(self.sprites()) == Config.BOARD_SIZE**2
def _can_move(self) -> bool: def _can_move(self) -> bool:
"""Check if any movement is possible on the board.""" """Check if any movement is possible on the board."""
@ -83,7 +96,7 @@ class Board(pygame.sprite.Group):
"""Check if the game is over.""" """Check if the game is over."""
return self._is_full() and not self._can_move() return self._is_full() and not self._can_move()
def restart(self) -> None: def reset(self) -> None:
"""Restart the game.""" """Reset the board."""
self.empty() self.empty()
self.generate_initial_blocks() self.initiate_game()

View File

@ -1,11 +1,25 @@
class Config: class Config:
FONT_FAMILY = "Roboto" FONT_FAMILY = "Roboto"
FONT_SIZE = 40 FONT_SIZE = 32
GRID_SIZE = 4
BOARD_SIZE = 4
BLOCK_SIZE = 50 BLOCK_SIZE = 50
WIDTH = GRID_SIZE * BLOCK_SIZE
HEIGHT = GRID_SIZE * BLOCK_SIZE + 100 # WIDTH = BOARD_SIZE * BLOCK_SIZE + BLOCK_SIZE
GRID_HEIGHT = GRID_SIZE * BLOCK_SIZE # HEIGHT = BOARD_SIZE * BLOCK_SIZE + BLOCK_SIZE * 2
GRID_WIDTH = GRID_SIZE * BLOCK_SIZE
BOARD_WIDTH = BOARD_SIZE * BLOCK_SIZE
BOARD_HEIGHT = BOARD_SIZE * BLOCK_SIZE
HEADER_WIDTH = BOARD_WIDTH + BLOCK_SIZE
HEADER_HEIGHT = BLOCK_SIZE
BOARD_X = BLOCK_SIZE // 2
BOARD_Y = HEADER_HEIGHT + BLOCK_SIZE // 2
SCREEN_WIDTH = HEADER_WIDTH
SCREEN_HEIGHT = BOARD_HEIGHT + BLOCK_SIZE + HEADER_HEIGHT
SCREEN_SIZE = SCREEN_WIDTH, SCREEN_HEIGHT
INITIAL_BLOCK_COUNT = 2 INITIAL_BLOCK_COUNT = 2
BLOCK_VALUE_PROBABILITY = 0.9 BLOCK_VALUE_PROBABILITY = 0.9

View File

@ -7,6 +7,7 @@ from .board import Board
from .color import Color from .color import Color
from .config import Config from .config import Config
from .logger import setup_logger from .logger import setup_logger
from .screens.header import Header
from .utils import Direction from .utils import Direction
@ -16,11 +17,10 @@ class Game:
logger.info("Initializing game") logger.info("Initializing game")
pygame.init() pygame.init()
self.screen: pygame.Surface = pygame.display.set_mode( self.screen: pygame.Surface = pygame.display.set_mode(Config.SCREEN_SIZE)
(Config.WIDTH, Config.HEIGHT)
)
pygame.display.set_caption("2048") pygame.display.set_caption("2048")
self.blocks = Board(self.screen) self.board = Board()
self.header = Header()
def run(self) -> None: def run(self) -> None:
"""Run the game loop.""" """Run the game loop."""
@ -31,12 +31,13 @@ class Game:
def _update(self) -> None: def _update(self) -> None:
"""Update the game.""" """Update the game."""
self.blocks.update() self.board.update()
def _render(self) -> None: def _render(self) -> None:
"""Render the game.""" """Render the game."""
self.screen.fill(Color.BG) self.screen.fill(Color.BG)
self.blocks.draw(self.screen) self.board.draw(self.screen)
self.header.draw(self.screen)
pygame.display.flip() pygame.display.flip()
def _hande_events(self) -> None: def _hande_events(self) -> None:
@ -57,16 +58,16 @@ class Game:
self.exit() self.exit()
def move_up(self) -> None: def move_up(self) -> None:
self.blocks.move(Direction.UP) self.board.move(Direction.UP)
def move_down(self) -> None: def move_down(self) -> None:
self.blocks.move(Direction.DOWN) self.board.move(Direction.DOWN)
def move_left(self) -> None: def move_left(self) -> None:
self.blocks.move(Direction.LEFT) self.board.move(Direction.LEFT)
def move_right(self) -> None: def move_right(self) -> None:
self.blocks.move(Direction.RIGHT) self.board.move(Direction.RIGHT)
def exit(self) -> None: def exit(self) -> None:
"""Exit the game.""" """Exit the game."""

View File

@ -0,0 +1,14 @@
import pygame
from ..color import Color
from ..config import Config
class Header:
def __init__(self) -> None:
self.rect = pygame.Rect(0, 0, Config.HEADER_WIDTH, Config.HEADER_HEIGHT)
self.score = 0 # TODO: Implement score
def draw(self, screen: pygame.Surface) -> None:
"""Draw the header."""
pygame.draw.rect(screen, Color.MAGENTA, self.rect, 2)