From 241e41892a10d3913c63935a8f9e14306e8a73cd Mon Sep 17 00:00:00 2001 From: omagdy7 Date: Mon, 8 May 2023 21:40:21 +0300 Subject: Made a Singeltion class GameState containg the current state of the game --- src/clyde.py | 17 +++---- src/game.py | 135 +++++++++++++++++++++++------------------------------- src/game_state.py | 46 +++++++++++++++++++ src/ghost.py | 21 +++++---- src/inky.py | 12 ++--- src/pinky.py | 10 ++-- 6 files changed, 135 insertions(+), 106 deletions(-) create mode 100644 src/game_state.py diff --git a/src/clyde.py b/src/clyde.py index 7dcf54e..e48a439 100644 --- a/src/clyde.py +++ b/src/clyde.py @@ -22,7 +22,7 @@ class Clyde(Ghost): return (27 * 30 + 15, 2 * 30 + 15) @override - def get_next_move(self, pacman, maze, screen, blinky): + def get_next_move(self, game_state, screen): default_tile = self.get_default_tile() dx = [1, 0, -1, 0] # right, down, left, up @@ -31,23 +31,24 @@ class Clyde(Ghost): inv_dir = [2, 3, 0, 1] ret = len(dx) * [math.inf] - bottom_left_corner = (2.5 * 30, (len(maze) - 1 - 1 - 0.5) * 30) + bottom_left_corner = ( + 2.5 * 30, (len(game_state.map.maze) - 1 - 1 - 0.5) * 30) forbidden = inv_dir[self.last_move] rand_pos = (0, 0) - if pacman.powerup: + if game_state.pacman.powerup: self.mode = MODE.FRIGHETENED rand_pos = random.randint(0, 900), random.randint(0, 990) - if pacman.powerup is False and self.mode == MODE.FRIGHETENED: + if game_state.pacman.powerup is False and self.mode == MODE.FRIGHETENED: self.mode = MODE.CHASING for i in range(len(dx)): nx = self.x + dx[i] * self.speed ny = self.y + dy[i] * self.speed - if self.check_collision(nx, ny, 30, 30, maze): + if self.check_collision(nx, ny, 30, 30, game_state.map.maze): if i != forbidden: if self.mode == MODE.SCATTERED: ret[i] = self.heuristic( @@ -56,7 +57,7 @@ class Clyde(Ghost): ret[i] = self.heuristic( (nx, ny), rand_pos[0], rand_pos[1]) elif self.mode == MODE.CHASING: - if self.is_eight_tiles_away(pacman): + if self.is_eight_tiles_away(game_state.pacman): ret[i] = self.heuristic( (nx, ny), bottom_left_corner[0], bottom_left_corner[1]) if settings.debug: @@ -64,9 +65,9 @@ class Clyde(Ghost): (self.x, self.y), 1) else: ret[i] = self.heuristic( - (nx, ny), pacman.x, pacman.y) + (nx, ny), game_state.pacman.x, game_state.pacman.y) if settings.debug: - pygame.draw.line(screen, self.color, (pacman.x, pacman.y), + pygame.draw.line(screen, self.color, (game_state.pacman.x, game_state.pacman.y), (self.x, self.y), 1) min_h = min(ret) diff --git a/src/game.py b/src/game.py index a904fad..4787c00 100644 --- a/src/game.py +++ b/src/game.py @@ -1,23 +1,16 @@ -from blinky import Blinky -from clyde import Clyde from direction import DIRECTION +from game_state import GameState from mode import MODE -from inky import Inky -from pinky import Pinky -from player import Player from settings import settings -import map as Map +from game_state import WIDTH, HEIGHT, TILE_WIDTH, TILE_HEIGHT import pygame -WIDTH = settings.width -HEIGHT = settings.height - class Game(): def __init__(self): self.settings = settings - def show_gameover_screen(self, screen, game_over): + def show_gameover_screen(self, screen, game_state, sprites): font = pygame.font.SysFont(None, 48) # Render the "Game Over" text to a surface @@ -38,14 +31,18 @@ class Game(): if event.type == pygame.KEYDOWN and event.key == pygame.K_r: # Reset the game and start again # Add your own code here to reset the game state - game_over[0] = False + self.reset_game(game_state, sprites) + game_state.game_over = False quit_game = True # Set the flag to True to break out of both loops break elif event.type == pygame.QUIT: - game_over[0] = True + game_state.game_over = True quit_game = True # Set the flag to True to break out of both loops break + def reset_game(self, game_state, sprites): + game_state.reset(sprites) + def run(self): # Initialize Pygame pygame.init() @@ -64,27 +61,14 @@ class Game(): clyde_sprite = pygame.image.load('../assets/clyde.png').convert_alpha() inky_sprite = pygame.image.load('../assets/inky.png').convert_alpha() + sprites = [sprite_sheet, blinky_sprite, + pinky_sprite, clyde_sprite, inky_sprite] + # Set the timer to trigger after 10,000 milliseconds (10 seconds) timer_event = pygame.USEREVENT + 1 pygame.time.set_timer(timer_event, 1000 * 10, 1) - # our beautiful maze - maze = Map.Map() - - # length of the map grid size - TILE_WIDTH = WIDTH // len(maze.maze[0]) - TILE_HEIGHT = HEIGHT // len(maze.maze) - - # Initialize the player and the ghosts - player = Player(sprite_sheet) - blinky = Blinky(blinky_sprite, 12 * TILE_WIDTH + - 15, 12 * TILE_HEIGHT + 15) - pinky = Pinky(pinky_sprite, 11 * TILE_WIDTH + - 15, 12 * TILE_HEIGHT + 15) - inky = Inky(inky_sprite, 13 * TILE_WIDTH + - 15, 12 * TILE_HEIGHT + 15) - clyde = Clyde(clyde_sprite, 14 * TILE_WIDTH + - 15, 12 * TILE_HEIGHT + 15) + game_state = GameState(sprites) # Set the pacman velocity dx = 0 @@ -101,10 +85,9 @@ class Game(): if settings.sound: pygame.mixer.music.play() siren_sound.play(-1) - is_game_over = [False] # Main game loop - while not is_game_over[0]: + while not game_state.game_over: # setting game fps clock.tick(settings.fps) @@ -120,98 +103,96 @@ class Game(): tx = dx ty = dy - is_pacman_alive = [True] - # Handling events for event in pygame.event.get(): if event.type == pygame.QUIT: - is_game_over[0] = True + game_state.game_over = True elif event.type == pygame.KEYDOWN: # Move the circle based on the pressed key if event.key == pygame.K_w: - player.direction = DIRECTION.UP - ty = -player.speed + game_state.pacman.direction = DIRECTION.UP + ty = -game_state.pacman.speed tx = 0 # Necssarry to move only horizontal or vertical elif event.key == pygame.K_s: - player.direction = DIRECTION.DOWN - ty = player.speed + game_state.pacman.direction = DIRECTION.DOWN + ty = game_state.pacman.speed tx = 0 # Necssarry to move only horizontal or vertical elif event.key == pygame.K_a: - player.direction = DIRECTION.LEFT - tx = -player.speed + game_state.pacman.direction = DIRECTION.LEFT + tx = -game_state.pacman.speed ty = 0 # Necssarry to move only horizontal or vertical elif event.key == pygame.K_d: - player.direction = DIRECTION.RIGHT - tx = player.speed + game_state.pacman.direction = DIRECTION.RIGHT + tx = game_state.pacman.speed ty = 0 # Necssarry to move only horizontal or vertical # Check for the timer event if event.type == timer_event: - pinky.mode = MODE.CHASING - inky.mode = MODE.CHASING - blinky.mode = MODE.CHASING - clyde.mode = MODE.CHASING + game_state.pinky.mode = MODE.CHASING + game_state.inky.mode = MODE.CHASING + game_state.blinky.mode = MODE.CHASING + game_state.clyde.mode = MODE.CHASING keys = pygame.key.get_pressed() # Simulates holding the key which adds better playability for pacman if keys[pygame.K_w]: - player.direction = DIRECTION.UP - ty = -player.speed + game_state.pacman.direction = DIRECTION.UP + ty = -game_state.pacman.speed tx = 0 elif keys[pygame.K_s]: - player.direction = DIRECTION.DOWN - ty = player.speed + game_state.pacman.direction = DIRECTION.DOWN + ty = game_state.pacman.speed tx = 0 elif keys[pygame.K_a]: - player.direction = DIRECTION.LEFT - tx = -player.speed + game_state.pacman.direction = DIRECTION.LEFT + tx = -game_state.pacman.speed ty = 0 elif keys[pygame.K_d]: - player.direction = DIRECTION.RIGHT - tx = player.speed + game_state.pacman.direction = DIRECTION.RIGHT + tx = game_state.pacman.speed ty = 0 # if tx and ty doesn't lead to colliding change the current # dx and dy to them and other wise # let pacman move in his previous direction - if player.check_collision(maze, tx, ty, TILE_WIDTH, TILE_HEIGHT): + if game_state.pacman.check_collision(game_state.map, tx, ty, TILE_WIDTH, TILE_HEIGHT): dx = tx dy = ty if dx < 0: - player.direction = DIRECTION.LEFT + game_state.pacman.direction = DIRECTION.LEFT elif dx > 0: - player.direction = DIRECTION.RIGHT + game_state.pacman.direction = DIRECTION.RIGHT elif dy < 0: - player.direction = DIRECTION.UP + game_state.pacman.direction = DIRECTION.UP elif dy > 0: - player.direction = DIRECTION.DOWN + game_state.pacman.direction = DIRECTION.DOWN - if player.check_collision(maze, dx, dy, TILE_WIDTH, TILE_HEIGHT): - player.x += dx - player.y += dy - player.x %= 900 + if game_state.pacman.check_collision(game_state.map, dx, dy, TILE_WIDTH, TILE_HEIGHT): + game_state.pacman.x += dx + game_state.pacman.y += dy + game_state.pacman.x %= 900 # Move ghosts - blinky.move(maze.maze, player, screen, is_pacman_alive, blinky) - pinky.move(maze.maze, player, screen, is_pacman_alive, blinky) - inky.move(maze.maze, player, screen, is_pacman_alive, blinky) - clyde.move(maze.maze, player, screen, is_pacman_alive, blinky) + game_state.blinky.move(game_state, screen) + game_state.pinky.move(game_state, screen) + game_state.inky.move(game_state, screen) + game_state.clyde.move(game_state, screen) # Draw the map on each frame - maze.draw_map(screen) + game_state.map.draw_map(screen) - # Draw the player and the ghosts - player.draw(screen, counter) - blinky.draw(screen, player.powerup, counter) - pinky.draw(screen, player.powerup, counter) - inky.draw(screen, player.powerup, counter) - clyde.draw(screen, player.powerup, counter) + # Draw the game_state.pacman and the ghosts + game_state.pacman.draw(screen, counter) + game_state.blinky.draw(screen, game_state.pacman.powerup, counter) + game_state.pinky.draw(screen, game_state.pacman.powerup, counter) + game_state.inky.draw(screen, game_state.pacman.powerup, counter) + game_state.clyde.draw(screen, game_state.pacman.powerup, counter) - if not is_pacman_alive[0]: + if not game_state.is_pacman_alive: self.show_gameover_screen( - screen, is_game_over) - is_pacman_alive[0] = True + screen, game_state, sprites) + game_state.is_pacman_alive = True else: # Update the screen pygame.display.flip() diff --git a/src/game_state.py b/src/game_state.py new file mode 100644 index 0000000..f722873 --- /dev/null +++ b/src/game_state.py @@ -0,0 +1,46 @@ +from blinky import Blinky +from clyde import Clyde +from inky import Inky +from pinky import Pinky +from player import Player +from settings import settings +import map as Map +import pygame + +WIDTH = settings.width +HEIGHT = settings.height +maze = Map.Map() +TILE_WIDTH = WIDTH // len(maze.maze[0]) +TILE_HEIGHT = HEIGHT // len(maze.maze) + + +class GameState(): + def __init__(self, sprites): + self.pacman = Player(sprites[0]) + self.blinky = Blinky(sprites[1], 12 * TILE_WIDTH + + 15, 12 * TILE_HEIGHT + 15) + self.pinky = Pinky(sprites[2], 11 * TILE_WIDTH + + 15, 12 * TILE_HEIGHT + 15) + self.inky = Inky(sprites[3], 13 * TILE_WIDTH + + 15, 12 * TILE_HEIGHT + 15) + self.clyde = Clyde(sprites[4], 14 * TILE_WIDTH + + 15, 12 * TILE_HEIGHT + 15) + self.map = Map.Map() + self.game_over = False + self.is_pacman_alive = True + + def reset(self, sprites): + self.pacman = Player(sprites[0]) + self.blinky = Blinky(sprites[1], 12 * TILE_WIDTH + + 15, 12 * TILE_HEIGHT + 15) + self.pinky = Pinky(sprites[2], 11 * TILE_WIDTH + + 15, 12 * TILE_HEIGHT + 15) + self.inky = Inky(sprites[3], 13 * TILE_WIDTH + + 15, 12 * TILE_HEIGHT + 15) + self.clyde = Clyde(sprites[4], 14 * TILE_WIDTH + + 15, 12 * TILE_HEIGHT + 15) + self.map = Map.Map() + self.game_over = False + self.is_pacman_alive = True + timer_event = pygame.USEREVENT + 1 + pygame.time.set_timer(timer_event, 1000 * 10, 1) diff --git a/src/ghost.py b/src/ghost.py index e4b4cf1..fc3adfe 100644 --- a/src/ghost.py +++ b/src/ghost.py @@ -63,7 +63,7 @@ class Ghost(): return True - def get_next_move(self, pacman, maze, screen, blinky): + def get_next_move(self, game_state, screen): default_tile = self.get_default_tile() @@ -73,28 +73,29 @@ class Ghost(): rand_pos = (0, 0) - if pacman.powerup: + if game_state.pacman.powerup: self.mode = MODE.FRIGHETENED rand_pos = random.randint(0, 900), random.randint(0, 990) - if pacman.powerup is False and self.mode == MODE.FRIGHETENED: + if game_state.pacman.powerup is False and self.mode == MODE.FRIGHETENED: self.mode = MODE.CHASING for i in range(len(dx)): nx = self.x + dx[i] * self.speed ny = self.y + dy[i] * self.speed - if self.check_collision(nx, ny, 30, 30, maze): + if self.check_collision(nx, ny, 30, 30, game_state.map.maze): if i != forbidden: if self.mode == MODE.SCATTERED: ret[i] = self.heuristic( (nx, ny), default_tile[0], default_tile[1]) elif self.mode == MODE.CHASING: - ret[i] = self.heuristic((nx, ny), pacman.x, pacman.y) + ret[i] = self.heuristic( + (nx, ny), game_state.pacman.x, game_state.pacman.y) elif self.mode == MODE.FRIGHETENED: ret[i] = self.heuristic( (nx, ny), rand_pos[0], rand_pos[1]) if settings.debug: - pygame.draw.line(screen, self.color, (pacman.x, pacman.y), + pygame.draw.line(screen, self.color, (game_state.pacman.x, game_state.pacman.y), (self.x, self.y), 1) min_h = min(ret) @@ -108,10 +109,10 @@ class Ghost(): min_idx = ret.index(min_h) return min_idx - def move(self, maze, pacman, screen, is_pacman_alive, blinky): - if abs(pacman.x - self.x) <= 15 and abs(pacman.y - self.y) <= 15: - is_pacman_alive[0] = False - min_idx = self.get_next_move(pacman, maze, screen, blinky) + def move(self, game_state, screen): + if abs(game_state.pacman.x - self.x) <= 15 and abs(game_state.pacman.y - self.y) <= 15: + game_state.is_pacman_alive = False + min_idx = self.get_next_move(game_state, screen) new_dx = dx[min_idx] * self.speed new_dy = dy[min_idx] * self.speed self.x += new_dx diff --git a/src/inky.py b/src/inky.py index 1f5bb8b..840b60b 100644 --- a/src/inky.py +++ b/src/inky.py @@ -48,7 +48,7 @@ class Inky(Ghost): return target @override - def get_next_move(self, pacman, maze, screen, blinky): + def get_next_move(self, game_state, screen): default_tile = self.get_default_tile() dx = [1, 0, -1, 0] @@ -67,16 +67,16 @@ class Inky(Ghost): if self.last_move == 3: forbidden = 1 - inter_tile = self.get_intermediate_tile(pacman) - target = self.get_target(inter_tile, blinky) + inter_tile = self.get_intermediate_tile(game_state.pacman) + target = self.get_target(inter_tile, game_state.blinky) rand_pos = (0, 0) - if pacman.powerup: + if game_state.pacman.powerup: self.mode = MODE.FRIGHETENED rand_pos = random.randint(0, 900), random.randint(0, 990) - if pacman.powerup is False and self.mode == MODE.FRIGHETENED: + if game_state.pacman.powerup is False and self.mode == MODE.FRIGHETENED: self.mode = MODE.CHASING if settings.debug: @@ -87,7 +87,7 @@ class Inky(Ghost): if i != forbidden: nx = self.x + dx[i] * self.speed ny = self.y + dy[i] * self.speed - if self.check_collision(nx, ny, 30, 30, maze): + if self.check_collision(nx, ny, 30, 30, game_state.map.maze): if self.mode == MODE.SCATTERED: ret[i] = self.heuristic( (nx, ny), default_tile[0], default_tile[1]) diff --git a/src/pinky.py b/src/pinky.py index 29949a7..be9e5dc 100644 --- a/src/pinky.py +++ b/src/pinky.py @@ -43,7 +43,7 @@ class Pinky(Ghost): return (27 * 30 + 15, 30 * 30 + 15) @override - def get_next_move(self, pacman, maze, screen, blinky): + def get_next_move(self, game_state, screen): default_tile = self.get_default_tile() dx = [1, 0, -1, 0] @@ -64,25 +64,25 @@ class Pinky(Ghost): rand_pos = (0, 0) - new_target = self.get_four_tiles_ahead_of_pacman(pacman) + new_target = self.get_four_tiles_ahead_of_pacman(game_state.pacman) if settings.debug: pygame.draw.circle(screen, self.color, (new_target[0], new_target[1]), 15) pygame.draw.circle(screen, self.color, default_tile, 15) - if pacman.powerup: + if game_state.pacman.powerup: self.mode = MODE.FRIGHETENED rand_pos = random.randint(0, 900), random.randint(0, 990) - if pacman.powerup is False and self.mode == MODE.FRIGHETENED: + if game_state.pacman.powerup is False and self.mode == MODE.FRIGHETENED: self.mode = MODE.CHASING for i in range(len(dx)): if i != forbidden: nx = self.x + dx[i] * self.speed ny = self.y + dy[i] * self.speed - if self.check_collision(nx, ny, 30, 30, maze): + if self.check_collision(nx, ny, 30, 30, game_state.map.maze): if self.mode == MODE.SCATTERED: ret[i] = self.heuristic( (nx, ny), default_tile[0], default_tile[1]) -- cgit v1.2.3 From aaf0194f9b5d93bd6612bc0b419c4b8f89b4aa21 Mon Sep 17 00:00:00 2001 From: omagdy7 Date: Mon, 8 May 2023 23:02:03 +0300 Subject: Added a simple Wining screen when the user collects all the food --- src/clyde.py | 10 +++++++- src/game.py | 77 ++++++++++++++++++++++++++++++++++++++++++++++++------- src/game_state.py | 4 +++ src/ghost.py | 19 +++++++++++--- src/inky.py | 6 ++++- src/map.py | 2 +- src/pinky.py | 9 +++---- src/player.py | 18 ++++++++----- 8 files changed, 118 insertions(+), 27 deletions(-) diff --git a/src/clyde.py b/src/clyde.py index e48a439..755eafd 100644 --- a/src/clyde.py +++ b/src/clyde.py @@ -19,7 +19,11 @@ class Clyde(Ghost): @override def get_default_tile(self): - return (27 * 30 + 15, 2 * 30 + 15) + return (2 * 30 + 15, 30 * 30 + 15) + + @override + def get_intial_tile(self): + return (14 * 30 + 15, 12 * 30 + 15) @override def get_next_move(self, game_state, screen): @@ -45,6 +49,10 @@ class Clyde(Ghost): if game_state.pacman.powerup is False and self.mode == MODE.FRIGHETENED: self.mode = MODE.CHASING + if settings.debug: + pygame.draw.line(screen, self.color, (game_state.pacman.x, game_state.pacman.y), + (self.x, self.y), 1) + for i in range(len(dx)): nx = self.x + dx[i] * self.speed ny = self.y + dy[i] * self.speed diff --git a/src/game.py b/src/game.py index 4787c00..a7efb67 100644 --- a/src/game.py +++ b/src/game.py @@ -11,16 +11,66 @@ class Game(): self.settings = settings def show_gameover_screen(self, screen, game_state, sprites): - font = pygame.font.SysFont(None, 48) + font = pygame.font.SysFont(None, 64) # Render the "Game Over" text to a surface - game_over_text = font.render( - "Game Over. Press R to try again.", True, (255, 255, 255)) + game_over_text_1 = font.render( + "Game Over", True, (255, 255, 255)) + game_over_text_2 = font.render( + "Press R to try again or Q to quit.", True, (255, 255, 255)) # Blit the "Game Over" text onto the screen - text_rect = game_over_text.get_rect( + text_rect_1 = game_over_text_1.get_rect( + center=(WIDTH/2, HEIGHT/2 - 75)) + text_rect_2 = game_over_text_2.get_rect( center=(WIDTH/2, HEIGHT/2)) - screen.blit(game_over_text, text_rect) + + screen.blit(game_over_text_1, text_rect_1) + screen.blit(game_over_text_2, text_rect_2) + + # Update the display + pygame.display.flip() + + quit_game = False # Initialize the flag variable + while not quit_game: + for event in pygame.event.get(): + if event.type == pygame.KEYDOWN and event.key == pygame.K_r: + # Reset the game and start again + # Add your own code here to reset the game state + self.reset_game(game_state, sprites) + game_state.game_over = False + quit_game = True # Set the flag to True to break out of both loops + break + elif event.type == pygame.KEYDOWN and event.key == pygame.K_q: + game_state.game_over = True + quit_game = True + break + elif event.type == pygame.QUIT: + game_state.game_over = True + quit_game = True # Set the flag to True to break out of both loops + break + + def show_wining_screen(self, screen, game_state, sprites): + font = pygame.font.SysFont(None, 64) + + # Render the "Game Over" text to a surface + wining_text_1 = font.render( + "Congratulation You Won!!", True, (255, 255, 255)) + wining_text_2 = font.render( + "Press R to play again or Q to quit", True, (255, 255, 255)) + + text_rect_1 = wining_text_1.get_rect( + center=(WIDTH/2, HEIGHT/2 - 75)) + text_rect_2 = wining_text_2.get_rect( + center=(WIDTH/2, HEIGHT/2)) + + # Blit the "Game Over" text onto the screen + text_rect_1 = wining_text_1.get_rect( + center=(WIDTH/2, HEIGHT/2)) + text_rect_2 = wining_text_2.get_rect( + center=(WIDTH/2, HEIGHT/2 + 100)) + screen.blit(wining_text_1, text_rect_1) + screen.blit(wining_text_2, text_rect_2) # Update the display pygame.display.flip() @@ -35,6 +85,10 @@ class Game(): game_state.game_over = False quit_game = True # Set the flag to True to break out of both loops break + elif event.type == pygame.KEYDOWN and event.key == pygame.K_q: + game_state.game_over = True + quit_game = True + break elif event.type == pygame.QUIT: game_state.game_over = True quit_game = True # Set the flag to True to break out of both loops @@ -62,7 +116,7 @@ class Game(): inky_sprite = pygame.image.load('../assets/inky.png').convert_alpha() sprites = [sprite_sheet, blinky_sprite, - pinky_sprite, clyde_sprite, inky_sprite] + pinky_sprite, inky_sprite, clyde_sprite] # Set the timer to trigger after 10,000 milliseconds (10 seconds) timer_event = pygame.USEREVENT + 1 @@ -155,7 +209,7 @@ class Game(): # if tx and ty doesn't lead to colliding change the current # dx and dy to them and other wise # let pacman move in his previous direction - if game_state.pacman.check_collision(game_state.map, tx, ty, TILE_WIDTH, TILE_HEIGHT): + if game_state.pacman.check_collision(game_state, tx, ty, TILE_WIDTH, TILE_HEIGHT): dx = tx dy = ty @@ -168,10 +222,10 @@ class Game(): elif dy > 0: game_state.pacman.direction = DIRECTION.DOWN - if game_state.pacman.check_collision(game_state.map, dx, dy, TILE_WIDTH, TILE_HEIGHT): + if game_state.pacman.check_collision(game_state, dx, dy, TILE_WIDTH, TILE_HEIGHT): game_state.pacman.x += dx game_state.pacman.y += dy - game_state.pacman.x %= 900 + game_state.pacman.x %= 900 # logic for portal # Move ghosts game_state.blinky.move(game_state, screen) @@ -189,6 +243,10 @@ class Game(): game_state.inky.draw(screen, game_state.pacman.powerup, counter) game_state.clyde.draw(screen, game_state.pacman.powerup, counter) + if game_state.food == 246: + self.show_wining_screen(screen, game_state, sprites) + + if not game_state.is_pacman_alive: self.show_gameover_screen( screen, game_state, sprites) @@ -198,4 +256,5 @@ class Game(): pygame.display.flip() # Quit Pygame + print(game_state.score) pygame.quit() diff --git a/src/game_state.py b/src/game_state.py index f722873..5ed98c0 100644 --- a/src/game_state.py +++ b/src/game_state.py @@ -26,7 +26,9 @@ class GameState(): self.clyde = Clyde(sprites[4], 14 * TILE_WIDTH + 15, 12 * TILE_HEIGHT + 15) self.map = Map.Map() + self.food = 0 self.game_over = False + self.score = 0 self.is_pacman_alive = True def reset(self, sprites): @@ -40,7 +42,9 @@ class GameState(): self.clyde = Clyde(sprites[4], 14 * TILE_WIDTH + 15, 12 * TILE_HEIGHT + 15) self.map = Map.Map() + self.food = 0 self.game_over = False self.is_pacman_alive = True + self.score = 0 timer_event = pygame.USEREVENT + 1 pygame.time.set_timer(timer_event, 1000 * 10, 1) diff --git a/src/ghost.py b/src/ghost.py index fc3adfe..c05eb1b 100644 --- a/src/ghost.py +++ b/src/ghost.py @@ -1,4 +1,5 @@ import pygame +import time import random import math from util import get_sprites @@ -34,7 +35,6 @@ class Ghost(): return abs(next_pos[0] - tx) + abs(next_pos[1] - ty) # checks if the current position of pacman is either a dot, big dot or free - def is_valid(self, maze, x, y): if x >= 0 and x < 30: # Necessary to make portals work is_dot = maze[y][x] == Map.D @@ -46,6 +46,9 @@ class Ghost(): def get_default_tile(self): return (75, 75) + def get_intial_tile(self): + return (12 * 30 + 15, 12 * 30 + 15) + # checks collision with pacman and obstacles returns false if there is # a collision and true otherwise @@ -63,6 +66,17 @@ class Ghost(): return True + def check_pacman_collision(self, game_state): + if game_state.pacman.powerup and abs(game_state.pacman.x - self.x) <= 30 and abs(game_state.pacman.y - self.y) <= 30: + initial_position = self.get_intial_tile() + time.sleep(1) + game_state.score += 200 + self.x = initial_position[0] + self.y = initial_position[1] + elif not game_state.pacman.powerup and abs(game_state.pacman.x - self.x) <= 30 and abs(game_state.pacman.y - self.y) <= 30: + if abs(game_state.pacman.x - self.x) <= 30 and abs(game_state.pacman.y - self.y) <= 30: + game_state.is_pacman_alive = False + def get_next_move(self, game_state, screen): default_tile = self.get_default_tile() @@ -110,8 +124,7 @@ class Ghost(): return min_idx def move(self, game_state, screen): - if abs(game_state.pacman.x - self.x) <= 15 and abs(game_state.pacman.y - self.y) <= 15: - game_state.is_pacman_alive = False + self.check_pacman_collision(game_state) min_idx = self.get_next_move(game_state, screen) new_dx = dx[min_idx] * self.speed new_dy = dy[min_idx] * self.speed diff --git a/src/inky.py b/src/inky.py index 840b60b..2b48ede 100644 --- a/src/inky.py +++ b/src/inky.py @@ -40,7 +40,11 @@ class Inky(Ghost): @override def get_default_tile(self): - return (2 * 30 + 15, 30 * 30 + 15) + return (27 * 30 + 15, 2 * 30 + 15) + + @override + def get_intial_tile(self): + return (13 * 30 + 15, 12 * 30 + 15) def get_target(self, inter_tile, blinky): target = (max(inter_tile[0] - (blinky.x - inter_tile[0]) % 900, 0), diff --git a/src/map.py b/src/map.py index c37a438..ce83952 100644 --- a/src/map.py +++ b/src/map.py @@ -118,4 +118,4 @@ class Map(): for j in range(cols): pos = (j * self.line_horizontal, i * self.line_vertical) self.draw_wall(screen, self.maze[i][j], pos) - # pygame.draw.rect(screen, 'red', (pos[0], pos[1], 32, 32), 2) + diff --git a/src/pinky.py b/src/pinky.py index be9e5dc..5f58f54 100644 --- a/src/pinky.py +++ b/src/pinky.py @@ -42,6 +42,10 @@ class Pinky(Ghost): def get_default_tile(self): return (27 * 30 + 15, 30 * 30 + 15) + @override + def get_intial_tile(self): + return (11 * 30 + 15, 12 * 30 + 15) + @override def get_next_move(self, game_state, screen): default_tile = self.get_default_tile() @@ -65,11 +69,6 @@ class Pinky(Ghost): rand_pos = (0, 0) new_target = self.get_four_tiles_ahead_of_pacman(game_state.pacman) - if settings.debug: - pygame.draw.circle(screen, self.color, - (new_target[0], new_target[1]), 15) - pygame.draw.circle(screen, self.color, - default_tile, 15) if game_state.pacman.powerup: self.mode = MODE.FRIGHETENED diff --git a/src/player.py b/src/player.py index 97d2ea5..92c4a84 100644 --- a/src/player.py +++ b/src/player.py @@ -17,22 +17,26 @@ class Player(): self.timer = None # checks if the current position of pacman is either a dot, big dot or free - def is_valid(self, maze, x, y): + def is_valid(self, game_state, x, y): if x >= 0 and x < 30: - is_dot = maze.maze[y][x] == Map.D - is_big_dot = maze.maze[y][x] == Map.BD - is_free = maze.maze[y][x] == 0 + is_dot = game_state.map.maze[y][x] == Map.D + is_big_dot = game_state.map.maze[y][x] == Map.BD + is_free = game_state.map.maze[y][x] == 0 if is_dot or is_big_dot: - maze.maze[y][x] = 0 + game_state.map.maze[y][x] = 0 + game_state.food += 1 + if is_dot: + game_state.score += 10 if is_big_dot: self.powerup = True self.timer = Timer(5 * 1000) + game_state.score += 50 return (is_dot or is_free or is_big_dot) return True # checks collision with pacman and obstacles returns false # if there is a collision and true otherwise - def check_collision(self, maze, dx, dy, tile_width, tile_height): + def check_collision(self, game_state, dx, dy, tile_width, tile_height): direct_x = [1, 0, -1, 0, 1, 1, -1, -1] direct_y = [0, 1, 0, -1, -1, 1, -1, 1] @@ -43,7 +47,7 @@ class Player(): ny = (self.y + ddy) + direct_y[i] * 14 x = nx // tile_width y = ny // tile_height - if not self.is_valid(maze, x, y): + if not self.is_valid(game_state, x, y): return False return True -- cgit v1.2.3 From 5b2e6b7e660865b6db9bfb61e1b1d0fecc536858 Mon Sep 17 00:00:00 2001 From: omagdy7 Date: Mon, 8 May 2023 23:18:26 +0300 Subject: Added EatenMode --- src/clyde.py | 7 +++++-- src/ghost.py | 15 ++++++++++++++- src/inky.py | 6 +++++- src/pinky.py | 6 +++++- 4 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/clyde.py b/src/clyde.py index 755eafd..2fd4aee 100644 --- a/src/clyde.py +++ b/src/clyde.py @@ -42,7 +42,7 @@ class Clyde(Ghost): rand_pos = (0, 0) - if game_state.pacman.powerup: + if game_state.pacman.powerup and self.mode != MODE.EATEN: self.mode = MODE.FRIGHETENED rand_pos = random.randint(0, 900), random.randint(0, 990) @@ -77,7 +77,10 @@ class Clyde(Ghost): if settings.debug: pygame.draw.line(screen, self.color, (game_state.pacman.x, game_state.pacman.y), (self.x, self.y), 1) - + elif self.mode == MODE.EATEN: + pos = self.get_intial_tile() + self.x = pos[0] + self.y = pos[1] min_h = min(ret) # Favour going up when there is a conflict diff --git a/src/ghost.py b/src/ghost.py index c05eb1b..8568ff4 100644 --- a/src/ghost.py +++ b/src/ghost.py @@ -3,6 +3,7 @@ import time import random import math from util import get_sprites +from timer import Timer from settings import settings from mode import MODE from direction import DIRECTION @@ -25,6 +26,7 @@ class Ghost(): self.color = color self.last_move = 3 # this represents the direction based on the dx, dy arrays self.speed = 3 + self.timer = None self.mode = MODE.SCATTERED def in_bounds(self, pos): @@ -69,6 +71,8 @@ class Ghost(): def check_pacman_collision(self, game_state): if game_state.pacman.powerup and abs(game_state.pacman.x - self.x) <= 30 and abs(game_state.pacman.y - self.y) <= 30: initial_position = self.get_intial_tile() + self.mode = MODE.EATEN + self.timer = Timer(2 * 1000) time.sleep(1) game_state.score += 200 self.x = initial_position[0] @@ -87,7 +91,7 @@ class Ghost(): rand_pos = (0, 0) - if game_state.pacman.powerup: + if game_state.pacman.powerup and self.mode != MODE.EATEN: self.mode = MODE.FRIGHETENED rand_pos = random.randint(0, 900), random.randint(0, 990) @@ -108,6 +112,10 @@ class Ghost(): elif self.mode == MODE.FRIGHETENED: ret[i] = self.heuristic( (nx, ny), rand_pos[0], rand_pos[1]) + elif self.mode == MODE.EATEN: + pos = self.get_intial_tile() + self.x = pos[0] + self.y = pos[1] if settings.debug: pygame.draw.line(screen, self.color, (game_state.pacman.x, game_state.pacman.y), (self.x, self.y), 1) @@ -134,6 +142,11 @@ class Ghost(): self.last_move = min_idx def draw(self, screen, powerup, counter): + if self.timer is not None: + elapsed_time = pygame.time.get_ticks() - self.timer.start + if elapsed_time > self.timer.duration: + self.mode = MODE.CHASING + radius = 30 // 2 pos = (self.x - radius, self.y - radius) if powerup: diff --git a/src/inky.py b/src/inky.py index 2b48ede..be2e62c 100644 --- a/src/inky.py +++ b/src/inky.py @@ -76,7 +76,7 @@ class Inky(Ghost): rand_pos = (0, 0) - if game_state.pacman.powerup: + if game_state.pacman.powerup and self.mode != MODE.EATEN: self.mode = MODE.FRIGHETENED rand_pos = random.randint(0, 900), random.randint(0, 990) @@ -101,6 +101,10 @@ class Inky(Ghost): elif self.mode == MODE.CHASING: ret[i] = self.heuristic( (nx, ny), target[0], target[1]) + elif self.mode == MODE.EATEN: + pos = self.get_intial_tile() + self.x = pos[0] + self.y = pos[1] min_h = min(ret) diff --git a/src/pinky.py b/src/pinky.py index 5f58f54..bb50c5b 100644 --- a/src/pinky.py +++ b/src/pinky.py @@ -70,7 +70,7 @@ class Pinky(Ghost): new_target = self.get_four_tiles_ahead_of_pacman(game_state.pacman) - if game_state.pacman.powerup: + if game_state.pacman.powerup and self.mode != MODE.EATEN: self.mode = MODE.FRIGHETENED rand_pos = random.randint(0, 900), random.randint(0, 990) @@ -91,6 +91,10 @@ class Pinky(Ghost): elif self.mode == MODE.CHASING: ret[i] = self.heuristic( (nx, ny), new_target[0], new_target[1]) + elif self.mode == MODE.EATEN: + pos = self.get_intial_tile() + self.x = pos[0] + self.y = pos[1] if settings.debug: pygame.draw.line(screen, self.color, (new_target), (self.x, self.y), 1) -- cgit v1.2.3 From 0164fb61ccc79e677c711b158359060a7d3a2873 Mon Sep 17 00:00:00 2001 From: omagdy7 Date: Mon, 8 May 2023 23:19:02 +0300 Subject: Checked some Todos in README --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 34c815c..3c627a9 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,8 @@ python3 macpan.py - [X] Add scattered mode for the ghosts - [X] Add firghtened mode for the ghosts -- [ ] Add powerups +- [X] Add Eaten mode for the ghosts +- [X] Add powerups - [ ] Setup a menu for the game - [ ] Setup a simple score system - [ ] Setup a proper sfx/audio for the game -- cgit v1.2.3