feat(game): add phantoms

This commit is contained in:
Kristofers Solo 2024-01-07 18:13:01 +02:00
parent c58bf61603
commit 4bd4ff00ad
4 changed files with 62 additions and 14 deletions

View File

@ -22,8 +22,8 @@ class Main(BaseScreen, SceenElement, TextScreen):
self._set_buttons()
self._initialize_increment_height()
self.settings = read_settings()
self.game_mode = mode
self.game: Optional[Game] = None
self.game_mode = mode
self.settings_screen: Optional[Settings] = None
def draw(self) -> None:

View File

@ -59,6 +59,7 @@ class Tetris(BaseScreen):
self._initialize_grid_surface()
self._initialize_field_and_tetromino()
self.tetromino: Tetromino
self.phantom_tetromino: Tetromino
self._initialize_game_state()
self._initialize_timers()
@ -76,12 +77,14 @@ class Tetris(BaseScreen):
self.update()
self._draw_background()
self.sprites.draw(self.surface)
self.phantom_sprites.draw(self.surface)
self._draw_border()
self._draw_grid()
def update(self) -> None:
self._update_display_surface()
self.sprites.update()
self.phantom_sprites.update()
def handle_events(self) -> None:
"""Handle player input events."""
@ -108,7 +111,9 @@ class Tetris(BaseScreen):
Returns:
True if the movement was successful, False otherwise.
"""
return self.tetromino.move_horizontal(Direction.LEFT)
moved = self.tetromino.move_horizontal(Direction.LEFT)
self._update_phantom_position()
return moved
def move_right(self) -> bool:
"""
@ -117,7 +122,10 @@ class Tetris(BaseScreen):
Returns:
True if the movement was successful, False otherwise.
"""
return self.tetromino.move_horizontal(Direction.RIGHT)
moved = self.tetromino.move_horizontal(Direction.RIGHT)
self._update_phantom_position()
return moved
def rotate(self) -> bool:
"""
@ -126,7 +134,9 @@ class Tetris(BaseScreen):
Returns:
True if the rotation was successful, False otherwise.
"""
return self.tetromino.rotate()
rotated = self.tetromino.rotate()
self._update_phantom_position()
return rotated
def rotate_reverse(self) -> bool:
"""
@ -135,7 +145,9 @@ class Tetris(BaseScreen):
Returns:
True if the rotation was successful, False otherwise.
"""
return self.tetromino.rotate(Rotation.COUNTER_CLOCKWISE)
rotated = self.tetromino.rotate(Rotation.COUNTER_CLOCKWISE)
self._update_phantom_position()
return rotated
def drop(self) -> bool:
"""
@ -150,6 +162,7 @@ class Tetris(BaseScreen):
"""Create a new tetromino and perform necessary actions."""
self._play_landing_sound()
self._check_finished_rows()
self.phantom_tetromino.kill()
self.game_over: bool = self._check_game_over()
if self.game_over:
@ -162,6 +175,15 @@ class Tetris(BaseScreen):
shape or self.get_next_figure(),
)
self.phantom_tetromino = Tetromino(
self.phantom_sprites,
None,
self.field,
self.tetromino.figure,
True,
)
self.phantom_tetromino.drop()
return self.tetromino
def _check_game_over(self) -> bool:
@ -281,6 +303,7 @@ class Tetris(BaseScreen):
def _draw_components(self) -> None:
"""Draw additional components like borders and grid."""
self.sprites.draw(self.surface)
self.phantom_sprites.draw(self.surface)
self._draw_border()
self._draw_grid()
@ -296,6 +319,7 @@ class Tetris(BaseScreen):
def _initialize_sprites(self) -> None:
"""Initialize the game sprites."""
self.sprites: pygame.sprite.Group[Block] = pygame.sprite.Group()
self.phantom_sprites: pygame.sprite.Group[Block] = pygame.sprite.Group()
def _initialize_grid_surface(self) -> None:
"""Initialize the grid surface."""
@ -314,6 +338,15 @@ class Tetris(BaseScreen):
self.field,
)
self.phantom_tetromino = Tetromino(
self.phantom_sprites,
None,
self.field,
self.tetromino.figure,
True,
)
self.phantom_tetromino.drop()
def _initialize_timers(self) -> None:
"""Initialize game timers."""
self.timers = Timers(
@ -356,6 +389,11 @@ class Tetris(BaseScreen):
"""Update the display surface."""
self.dispaly_surface.blit(self.surface, CONFIG.game.pos)
def _update_phantom_position(self) -> None:
new_positions = [block.pos.copy() for block in self.tetromino.blocks]
self.phantom_tetromino.update_block_positions(new_positions)
self.phantom_tetromino.drop()
def _draw_background(self) -> None:
"""Fill the game surface with background color."""
self.surface.fill(CONFIG.colors.bg_float)
@ -445,6 +483,7 @@ class Tetris(BaseScreen):
def _reset_game_state(self) -> None:
"""Reset the game state."""
self.sprites.empty()
self.phantom_sprites.empty()
self._initialize_field_and_tetromino()
self._initialize_game_state()
self.update_score(self.lines, self.score, self.level)

View File

@ -4,6 +4,8 @@ import numpy as np
import pygame
from utils import CONFIG, Rotation, Size
from game.log import log
class Block(pygame.sprite.Sprite):
"""
@ -27,8 +29,10 @@ class Block(pygame.sprite.Sprite):
group: pygame.sprite.Group,
pos: pygame.Vector2,
color: str,
phantom: bool = False,
) -> None:
super().__init__(group)
self.phantom = phantom
self._initialize_image(color)
self._initialize_positions(pos)
@ -91,6 +95,8 @@ class Block(pygame.sprite.Sprite):
color: Color of the block.
"""
self.image = pygame.Surface(CONFIG.game.cell)
if self.phantom:
self.image.set_alpha(75)
self.image.fill(color)
def _initialize_positions(self, pos: pygame.Vector2) -> None:

View File

@ -31,15 +31,17 @@ class Tetromino:
def __init__(
self,
group: pygame.sprite.Group,
create_new: Callable[[Optional[Figure]], "Tetromino"],
create_new: Optional[Callable[[Optional[Figure]], "Tetromino"]],
field: np.ndarray[Optional[Block], Any],
shape: Optional[Figure] = None,
phantom: bool = False,
) -> None:
self.figure: Figure = self._generate_figure(shape)
self.block_positions: list[pygame.Vector2] = self.figure.value.shape
self.color: str = self.figure.value.color
self.create_new = create_new
self.field = field
self.phantom = phantom
self.blocks = self._initialize_blocks(group)
def move_down(self) -> bool:
@ -59,7 +61,8 @@ class Tetromino:
for block in self.blocks:
self.field[int(block.pos.y), int(block.pos.x)] = block
self.create_new(None)
if self.create_new:
self.create_new(None)
return False
@ -102,7 +105,7 @@ class Tetromino:
]
if self._are_new_positions_valid(new_positions):
self._update_block_positions(new_positions)
self.update_block_positions(new_positions)
return True
if any(pos.x < 0 for pos in new_positions):
@ -112,10 +115,6 @@ class Tetromino:
return False
def next_rotation(self) -> "Tetromino":
self.rotate()
return self
def drop(self) -> bool:
"""
Drops the Tetromino to the bottom of the game field.
@ -130,6 +129,10 @@ class Tetromino:
return True
def kill(self) -> None:
for block in self.blocks:
block.kill()
def check_collision(self, direction: Direction) -> bool:
"""
Checks if there is a collision in the given direction.
@ -181,7 +184,7 @@ class Tetromino:
for block in self.blocks
)
def _update_block_positions(self, new_positions: list[pygame.Vector2]) -> None:
def update_block_positions(self, new_positions: list[pygame.Vector2]) -> None:
"""
Updates the positions of Tetromino blocks.
@ -219,7 +222,7 @@ class Tetromino:
List of initialized blocks.
"""
return [
Block(group=group, pos=pos, color=self.color)
Block(group=group, pos=pos, color=self.color, phantom=self.phantom)
for pos in self.block_positions
]