From 6de87ac0021028ba58d9fcec6921591cb290116a Mon Sep 17 00:00:00 2001 From: IM23a-bachmannj2 Date: Tue, 10 Dec 2024 21:13:01 +0100 Subject: [PATCH] gamegrid, falling, Tetrominos, collision and deleting rows, GUI Menus and Score --- game_manager.py | 13 ++++ main.py | 157 ++++++++++++++++++++++++++++++++++++------------ settings.py | 19 +++++- tetrominos.py | 7 ++- 4 files changed, 156 insertions(+), 40 deletions(-) diff --git a/game_manager.py b/game_manager.py index 2ebe3a8..e3d416d 100644 --- a/game_manager.py +++ b/game_manager.py @@ -1,4 +1,15 @@ import pygame +import settings + + +#game states +def draw_text(surface, text, size, x, y, color): + """Utility function to render text onto a surface.""" + font = pygame.font.Font(None, size) # Use default font + text_surface = font.render(text, True, color) + text_rect = text_surface.get_rect(center=(x, y)) + surface.blit(text_surface, text_rect) + class Grid(): def __init__(self, rows, cols, cell_size): @@ -51,3 +62,5 @@ class Grid(): new_grid = [row for row in self.grid if not all(cell == 1 for cell in row)] cleared_rows = len(self.grid) - len(new_grid) self.grid = [[0] * self.cols for _ in range(cleared_rows)] + new_grid + + settings.game_score += 100 * cleared_rows diff --git a/main.py b/main.py index fb49e34..49d663a 100644 --- a/main.py +++ b/main.py @@ -1,74 +1,155 @@ import pygame, sys from settings import * -from game_manager import Grid +from game_manager import Grid, draw_text from tetrominos import Tetrominos +import settings + + + + +def setup(): + pygame.init() + global screen + screen = pygame.display.set_mode((width, height)) + global clock + clock = pygame.time.Clock() + pygame.display.set_caption("Tetris") + icon_img = pygame.image.load('assets/icon.png') + pygame.display.set_icon(icon_img) + state_screen(screen, game_state) + +def state_screen(screen, game_state): + """Display the start screen.""" + width = 300 + screen = pygame.display.set_mode((width, height)) + + surface = pygame.Surface((WIDTH, HEIGHT)) + surface.fill((0, 0, 0)) # Black background + + if game_state: + # Draw text + draw_text(surface, "TETRIS", 50, WIDTH // 2, HEIGHT // 2 - 50, (255, 255, 255)) + draw_text(surface, "Press ENTER to Start", 30, WIDTH // 2, HEIGHT // 2 + 50, (200, 200, 200)) + + else: + draw_text(surface, "Game Over", 50, WIDTH // 2, HEIGHT // 2 - 50, (255, 0, 0)) + draw_text(surface, "Press Enter to Restart", 30, WIDTH // 2, HEIGHT // 2 + 50, (200, 200, 200)) + + # Display the surface + screen.blit(surface, (0, 0)) + pygame.display.update() + + # Wait for the player to press ENTER + while True: + for event in pygame.event.get(): + if event.type == pygame.QUIT: + pygame.quit() + sys.exit() + elif event.type == pygame.KEYDOWN and event.key == pygame.K_RETURN: + game_state = True + settings.game_score = 0 + main() + return # Exit the start screen + +def pause_menu(screen): + """Render the pause menu.""" + screen.fill((0, 0, 0)) # Black background + draw_text(screen, "Game Paused", 50, 450 // 2, HEIGHT // 2 - 50, (255, 255, 255)) + draw_text(screen, "Press ESC to Resume", 30, 450 // 2, HEIGHT // 2 + 10, (200, 200, 200)) + pygame.display.update() def main(): - pygame.init() + + width = 450 screen = pygame.display.set_mode((width, height)) - clock = pygame.time.Clock() - pygame.display.set_caption("Tetris") + + grid_surface = pygame.Surface((g_width, g_height)) # Create the grid and tetromino game_grid = Grid(rows, cols, cell_size) tetromino = Tetrominos(cols, cell_size) fall_timer = 0 - fall_interval = 1000 // falling_speed # Falling interval in milliseconds + + fall_interval = 500 move_timer = 0 move_interval = 100 while True: - screen.fill((0, 153, 255)) # Background color + screen.fill((138, 138, 138)) + grid_surface.fill((87, 87, 87)) # Background color + current_time = pygame.time.get_ticks() for event in pygame.event.get(): if event.type == pygame.QUIT: sys.exit() elif event.type == pygame.KEYDOWN: - if event.key == pygame.K_UP: + if event.key == pygame.K_UP and settings.gamestate == "playing": rotated_shape = [list(row) for row in zip(*tetromino.shape[::-1])] if not game_grid.check_collision(rotated_shape, tetromino.x, tetromino.y): tetromino.shape = rotated_shape # Apply rotation + elif event.key == pygame.K_SPACE and settings.gamestate == "playing": + tetromino.instant_drop(game_grid) # Perform instant drop + game_grid.add_tetromino(tetromino) # Lock tetromino in place + game_grid.check_full_row() + tetromino = Tetrominos(cols, cell_size) + elif event.key == pygame.K_ESCAPE: # Pause the game + if settings.gamestate == "playing": + settings.gamestate = "paused" + elif settings.gamestate == "paused": + settings.gamestate = "playing" - keys = pygame.key.get_pressed() - if keys[pygame.K_RIGHT]: - if current_time - move_timer > move_interval: # Ensure delay between movements - if not game_grid.check_collision(tetromino.shape, tetromino.x + 1, tetromino.y): - tetromino.move(1, 0) # Move right - move_timer = current_time # Reset timer - elif keys[pygame.K_LEFT]: - if current_time - move_timer > move_interval: # Ensure delay between movements - if not game_grid.check_collision(tetromino.shape, tetromino.x - 1, tetromino.y): - tetromino.move(-1, 0) # Move left - move_timer = current_time # Reset timer + if settings.gamestate == "playing": - # Handle automatic falling based on timer - if current_time - fall_timer > fall_interval: - if not game_grid.check_collision(tetromino.shape, tetromino.x, tetromino.y + 1): - tetromino.move(0, 1) # Move down - else: - # Collision detected, lock the tetromino in place - game_grid.add_tetromino(tetromino) - game_grid.check_full_row() - tetromino = Tetrominos(cols, cell_size) # Spawn a new tetromino + keys = pygame.key.get_pressed() + if keys[pygame.K_RIGHT]: + if current_time - move_timer > move_interval: # Ensure delay between movements + if not game_grid.check_collision(tetromino.shape, tetromino.x + 1, tetromino.y): + tetromino.move(1, 0) # Move right + move_timer = current_time # Reset timer + elif keys[pygame.K_LEFT]: + if current_time - move_timer > move_interval: # Ensure delay between movements + if not game_grid.check_collision(tetromino.shape, tetromino.x - 1, tetromino.y): + tetromino.move(-1, 0) # Move left + move_timer = current_time # Reset timer - # Check if game is over - if game_grid.check_collision(tetromino.shape, tetromino.x, tetromino.y): - print("Game Over") - sys.exit() + # Handle automatic falling based on timer + if current_time - fall_timer > fall_interval: + if not game_grid.check_collision(tetromino.shape, tetromino.x, tetromino.y + 1): + tetromino.move(0, 1) # Move down + else: + # Collision detected, lock the tetromino in place + game_grid.add_tetromino(tetromino) + game_grid.check_full_row() + tetromino = Tetrominos(cols, cell_size) # Spawn a new tetromino - fall_timer = current_time + # Check if game is over + if game_grid.check_collision(tetromino.shape, tetromino.x, tetromino.y): + game_state = False + state_screen(screen, game_state) - # Draw the grid and tetromino - game_grid.draw_grid(screen) - tetromino.draw(screen) + fall_timer = current_time - pygame.display.update() - clock.tick(60) # Fixed frame rate for smooth movement + + # Draw the grid and tetromino + game_grid.draw_grid(grid_surface) + tetromino.draw(grid_surface) + + #draw score + draw_text(screen, f'Score: {settings.game_score}', 30, width -75, 100 , (255, 255, 255)) + + screen.blit(grid_surface) + + pygame.display.update() + clock.tick(fps) + + elif settings.gamestate == "paused": + # Render the pause menu + pause_menu(screen) if __name__ == '__main__': - main() + setup() diff --git a/settings.py b/settings.py index ecd48c2..83a549d 100644 --- a/settings.py +++ b/settings.py @@ -1,10 +1,27 @@ # Variables + +#screen size global height, width height, width = 600, 300 +#grid surface +g_height, g_width = 600, 300 + +#start surface size +HEIGHT, WIDTH = 600, 300 + +#state of the game +game_state = True + +#score +game_score = 0 + rows = 20 cols = 10 cell_size = 30 -falling_speed = 5 \ No newline at end of file +fps = 60 + +global gamestate # Add game state variable +gamestate = "playing" \ No newline at end of file diff --git a/tetrominos.py b/tetrominos.py index d9dc1ab..16d58f3 100644 --- a/tetrominos.py +++ b/tetrominos.py @@ -54,4 +54,9 @@ class Tetrominos: def move(self, dx, dy): """Move the tetromino.""" self.x += dx - self.y += dy \ No newline at end of file + self.y += dy + + def instant_drop(self, grid): + """Move the tetromino to the lowest possible position.""" + while not grid.check_collision(self.shape, self.x, self.y + 1): + self.y += 1