From 68f17e149ad49e63b05bb53ced64c74f4a372c4f Mon Sep 17 00:00:00 2001 From: omagdy7 Date: Wed, 19 Apr 2023 06:07:55 +0200 Subject: Renamed some files and did a bit of refactoring --- src/Direction.py | 7 -- src/Game.py | 193 ------------------------------------------------------- src/Ghost.py | 96 --------------------------- src/Player.py | 29 --------- src/blinky.py | 2 +- src/clyde.py | 2 +- src/direction.py | 7 ++ src/game.py | 169 ++++++++++++++++++++++++++++++++++++++++++++++++ src/ghost.py | 82 +++++++++++++++++++++++ src/inky.py | 2 +- src/macpan.py | 6 +- src/pinky.py | 6 +- src/player.py | 55 ++++++++++++++++ 13 files changed, 321 insertions(+), 335 deletions(-) delete mode 100644 src/Direction.py delete mode 100644 src/Game.py delete mode 100644 src/Ghost.py delete mode 100644 src/Player.py create mode 100644 src/direction.py create mode 100644 src/game.py create mode 100644 src/ghost.py create mode 100644 src/player.py (limited to 'src') diff --git a/src/Direction.py b/src/Direction.py deleted file mode 100644 index 076a754..0000000 --- a/src/Direction.py +++ /dev/null @@ -1,7 +0,0 @@ -from enum import Enum - -class DIRECTION(Enum): - UP = 1 - DOWN = 2 - RIGHT = 3 - LEFT = 4 diff --git a/src/Game.py b/src/Game.py deleted file mode 100644 index 0d517a1..0000000 --- a/src/Game.py +++ /dev/null @@ -1,193 +0,0 @@ -import Player -from pinky import Pinky -from blinky import Blinky -from inky import Inky -from clyde import Clyde -from Direction import DIRECTION -import settings as Settings -import map as Map -import pygame - - -class Game(): - def __init__(self): - self.settings = Settings.settings - - def init(self): - # Initialize Pygame - pygame.init() - - # Set the dimensions of the window - screen = pygame.display.set_mode( - (Settings.settings.width, Settings.settings.height)) - - # Sprite sheet for pacman - sprite_sheet = pygame.image.load( - '../assets/pacman_left_sprite.png').convert_alpha() - blinky_sprite = pygame.image.load( - '../assets/blinky.png').convert_alpha() - pinky_sprite = pygame.image.load( - '../assets/pinky.png').convert_alpha() - clyde_sprite = pygame.image.load( - '../assets/clyde.png').convert_alpha() - inky_sprite = pygame.image.load( - '../assets/inky.png').convert_alpha() - - player = Player.Player(sprite_sheet) - blinky = Blinky(blinky_sprite,75, 75) - pinky = Pinky(pinky_sprite, 27 * 30, 30 * 30 + 15) - inky = Inky(inky_sprite, 75, 30 * 30 + 15) - clyde = Clyde(clyde_sprite, 27 * 30 + 15, 75) - - # Set the pacman velocity - dx = 0 - dy = 0 - - # counter used to cycle through pacman sprite animation - counter = 0 - - clock = pygame.time.Clock() - - - maze = Map.Map() - - # length of the map grid size - grid_x = Settings.settings.width // len(maze.maze[0]) - grid_y = Settings.settings.height // len(maze.maze) - - - # Checks collision with walls - - # checks if the current position of pacman is either a dot, big dot or free - def is_valid(x, y): - is_dot = maze.maze[y][x] == Map.D - is_big_dot = maze.maze[y][x] == Map.BD - is_free = maze.maze[y][x] == 0 - if is_dot or is_big_dot: - maze.maze[y][x] = 0 - # munch_sound.play(1, fade_ms=1) - - return (is_dot or is_free or is_big_dot) - - - # checks collision with pacman and obstacles returns false if there is a collision and true otherwise - def check_collision(dx, dy): - direct_x = [1, 0, -1, 0, 1, 1, -1, -1] - direct_y = [0, 1, 0, -1, -1, 1, -1, 1] - - for i in range(len(direct_x)): - nx = (player.x + dx) + direct_x[i] * 14 - ny = (player.y + dy) + direct_y[i] * 14 - x = nx // grid_x - y = ny // grid_y - if not is_valid(x, y): - return False - - return True - - pygame.mixer.music.load('../assets/sfx/game_start.wav') - siren_sound = pygame.mixer.Sound('../assets/sfx/siren_1.wav') - munch_sound = pygame.mixer.Sound('../assets/sfx/munch_1.wav') - - pygame.mixer.music.play() - siren_sound.play(-1) - running = True - - # Main game loop - while running: - # setting game fps - clock.tick(Settings.settings.fps) - - - - # counter logic for cycling between pacman different sprites - if counter < 19: - counter += 1 - else: - counter = 0 - - screen.fill((0, 0, 0)) # Clear the screen - - # Temporary values for delta_x and delta_y in the position of pacman - tx = dx - ty = dy - - # Handling events - for event in pygame.event.get(): - if event.type == pygame.QUIT: - running = False - elif event.type == pygame.KEYDOWN: - # Move the circle based on the pressed key - # if not pygame.mixer.get_busy(): - if event.key == pygame.K_w: - player.direction = DIRECTION.UP - ty = -player.speed - tx = 0 # Necssarry to move only horizontal or vertical - elif event.key == pygame.K_s: - player.direction = DIRECTION.DOWN - ty = player.speed - tx = 0 # Necssarry to move only horizontal or vertical - elif event.key == pygame.K_a: - player.direction = DIRECTION.LEFT - tx = -player.speed - ty = 0 # Necssarry to move only horizontal or vertical - elif event.key == pygame.K_d: - player.direction = DIRECTION.RIGHT - tx = player.speed - ty = 0 # Necssarry to move only horizontal or vertical - - keys = pygame.key.get_pressed() - # if not pygame.mixer.get_busy(): - if keys[pygame.K_w]: - ty = -player.speed - tx = 0 - elif keys[pygame.K_s]: - ty = player.speed - tx = 0 - elif keys[pygame.K_a]: - tx = -player.speed - ty = 0 - elif keys[pygame.K_d]: - tx = player.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 check_collision(tx, ty): - dx = tx - dy = ty - - if dx < 0: - player.direction = DIRECTION.LEFT - elif dx > 0: - player.direction = DIRECTION.RIGHT - elif dy < 0: - player.direction = DIRECTION.UP - elif dy > 0: - player.direction = DIRECTION.DOWN - - if check_collision(dx, dy): - player.x += dx - player.y += dy - - - blinky.move(maze.maze, player) - pinky.move(maze.maze, player) - inky.move(maze.maze, player) - clyde.move(maze.maze, player) - - maze.draw_map(screen) - - player.draw(screen, counter) - blinky.draw(screen) - pinky.draw(screen) - inky.draw(screen) - clyde.draw(screen) - - - # Update the screen - pygame.display.flip() - - # Quit Pygame - pygame.quit() diff --git a/src/Ghost.py b/src/Ghost.py deleted file mode 100644 index 668c943..0000000 --- a/src/Ghost.py +++ /dev/null @@ -1,96 +0,0 @@ -import math -from util import get_sprites -from settings import settings -import map as Map - -class Ghost(): - def __init__(self,sprite_sheet, color, x, y): - self.x = x - self.y = y - self.sprite = get_sprites(sprite_sheet) - self.color = color - self.last_move = 3 - self.speed = 3 - - def in_bounds(self, pos): - (x, y) = pos - return (x >= 0) and (y >= 0) and (x < settings.width - 30) and (y < settings.height) - - def heuristic(self, next_pos, tx, ty): - 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): - is_dot = maze[y][x] == Map.D - is_big_dot = maze[y][x] == Map.BD - is_free = maze[y][x] == 0 - return (is_dot or is_free or is_big_dot) - - - # checks collision with pacman and obstacles returns false if there is a collision and true otherwise - def check_collision(self, nx, ny, gx, gy, maze): - direct_x = [1, 0, -1, 0, 1, 1, -1, -1] - direct_y = [0, 1, 0, -1, -1, 1, -1, 1] - - - for i in range(len(direct_x)): - px = nx + direct_x[i] * 14 - py = ny + direct_y[i] * 14 - x = px // gx - y = py // gy - if not self.in_bounds((px, py)) or not self.is_valid(maze, x, y): - return False - - return True - - - def get_next_move(self, pacman, maze): - dx = [1, 0, -1, 0] - dy = [0, 1, 0, -1] - - ret = len(dx) * [math.inf] - - forbidden = 0 - - if self.last_move == 0: - forbidden = 2 - if self.last_move == 1: - forbidden = 3 - if self.last_move == 2: - forbidden = 0 - if self.last_move == 3: - forbidden = 1 - - 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): - ret[i] = self.heuristic((nx, ny), pacman.x, pacman.y) - - min_idx = ret.index(min(ret)) - return min_idx - - - def move(self, maze, pacman): - min_idx = self.get_next_move(pacman, maze) - dx = [1, 0, -1, 0] - dy = [0, 1, 0, -1] - new_dx = dx[min_idx] * self.speed - new_dy = dy[min_idx] * self.speed - self.x += new_dx - self.y += new_dy - self.last_move = min_idx - - def draw(self, screen): - radius = 30 // 2 - pos = (self.x - radius , self.y - radius) - if self.last_move == 0: - screen.blit(self.sprite[2], pos) - elif self.last_move == 1: - screen.blit(self.sprite[0], pos) - elif self.last_move == 2: - screen.blit(self.sprite[3], pos) - elif self.last_move == 3: - screen.blit(self.sprite[1], pos) diff --git a/src/Player.py b/src/Player.py deleted file mode 100644 index 21c1f7e..0000000 --- a/src/Player.py +++ /dev/null @@ -1,29 +0,0 @@ -from typing import List -from Direction import DIRECTION -from util import get_sprites -import pygame - - -class Player(): - def __init__(self, sprite_sheet): - self.x = 30 * 17 - 15 - self.y = 30 * 25 - 15 - self.sprite = get_sprites(sprite_sheet) - self.speed = 6 - self.direction = DIRECTION.LEFT - - def draw(self, screen, counter): - radius = 30 // 2 - pos = (self.x - radius , self.y - radius) - # pygame.draw.circle(screen, 'green', pos, radius) - if self.direction == DIRECTION.UP: - screen.blit(pygame.transform.rotate( - self.sprite[counter // 5], 270), pos) - elif self.direction == DIRECTION.DOWN: - screen.blit(pygame.transform.rotate( - self.sprite[counter // 5], 90), pos) - elif self.direction == DIRECTION.RIGHT: - screen.blit(pygame.transform.flip( - self.sprite[counter // 5], True, False), pos) - elif self.direction == DIRECTION.LEFT: - screen.blit(self.sprite[counter // 5], pos) diff --git a/src/blinky.py b/src/blinky.py index ca647e3..eee44a8 100644 --- a/src/blinky.py +++ b/src/blinky.py @@ -1,4 +1,4 @@ -from Ghost import Ghost +from ghost import Ghost class Blinky(Ghost): def __init__(self, sprite_sheet, x, y): diff --git a/src/clyde.py b/src/clyde.py index ae96bfb..560c7cb 100644 --- a/src/clyde.py +++ b/src/clyde.py @@ -1,4 +1,4 @@ -from Ghost import Ghost +from ghost import Ghost class Clyde(Ghost): def __init__(self, sprite_sheet, x, y): diff --git a/src/direction.py b/src/direction.py new file mode 100644 index 0000000..2ee3ba1 --- /dev/null +++ b/src/direction.py @@ -0,0 +1,7 @@ +from enum import Enum + +class DIRECTION(Enum): + RIGHT = 0 + DOWN = 1 + LEFT = 2 + UP = 3 diff --git a/src/game.py b/src/game.py new file mode 100644 index 0000000..b2ff3b7 --- /dev/null +++ b/src/game.py @@ -0,0 +1,169 @@ +from blinky import Blinky +from clyde import Clyde +from direction import DIRECTION +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 + + +class Game(): + def __init__(self): + self.settings = settings + + def run(self): + # Initialize Pygame + pygame.init() + + # Set the dimensions of the window + screen = pygame.display.set_mode((WIDTH, HEIGHT)) + + # Sprite sheet for pacman + sprite_sheet = pygame.image.load( '../assets/pacman_left_sprite.png').convert_alpha() + + # Sprite sheets for the ghosts + blinky_sprite = pygame.image.load('../assets/blinky.png').convert_alpha() + pinky_sprite = pygame.image.load( '../assets/pinky.png').convert_alpha() + clyde_sprite = pygame.image.load( '../assets/clyde.png').convert_alpha() + inky_sprite = pygame.image.load( '../assets/inky.png').convert_alpha() + + # 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,75, 75) + pinky = Pinky(pinky_sprite, 27 * 30, 30 * 30 + 15) + inky = Inky(inky_sprite, 75, 30 * 30 + 15) + clyde = Clyde(clyde_sprite, 27 * 30 + 15, 75) + + # Set the pacman velocity + dx = 0 + dy = 0 + + # counter used to cycle through pacman sprite animation + counter = 0 + + clock = pygame.time.Clock() + + pygame.mixer.music.load('../assets/sfx/game_start.wav') + siren_sound = pygame.mixer.Sound('../assets/sfx/siren_1.wav') + munch_sound = pygame.mixer.Sound('../assets/sfx/munch_1.wav') + + pygame.mixer.music.play() + siren_sound.play(-1) + running = True + + + # Main game loop + while running: + # setting game fps + clock.tick(settings.fps) + + # counter logic for cycling between pacman different sprites + if counter < 19: + counter += 1 + else: + counter = 0 + + screen.fill((0, 0, 0)) # Clear the screen + + # Temporary values for delta_x and delta_y in the position of pacman + tx = dx + ty = dy + + # Handling events + for event in pygame.event.get(): + if event.type == pygame.QUIT: + running = False + 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 + tx = 0 # Necssarry to move only horizontal or vertical + elif event.key == pygame.K_s: + player.direction = DIRECTION.DOWN + ty = player.speed + tx = 0 # Necssarry to move only horizontal or vertical + elif event.key == pygame.K_a: + player.direction = DIRECTION.LEFT + tx = -player.speed + ty = 0 # Necssarry to move only horizontal or vertical + elif event.key == pygame.K_d: + player.direction = DIRECTION.RIGHT + tx = player.speed + ty = 0 # Necssarry to move only horizontal or vertical + + 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 + tx = 0 + elif keys[pygame.K_s]: + player.direction = DIRECTION.DOWN + ty = player.speed + tx = 0 + elif keys[pygame.K_a]: + player.direction = DIRECTION.LEFT + tx = -player.speed + ty = 0 + elif keys[pygame.K_d]: + player.direction = DIRECTION.RIGHT + tx = player.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): + dx = tx + dy = ty + + if dx < 0: + player.direction = DIRECTION.LEFT + elif dx > 0: + player.direction = DIRECTION.RIGHT + elif dy < 0: + player.direction = DIRECTION.UP + elif dy > 0: + player.direction = DIRECTION.DOWN + + if player.check_collision(maze, dx, dy, TILE_WIDTH, TILE_HEIGHT): + player.x += dx + player.y += dy + + + # Move ghosts + blinky.move(maze.maze, player) + pinky.move(maze.maze, player) + inky.move(maze.maze, player) + clyde.move(maze.maze, player) + + # Draw the map on each frame + maze.draw_map(screen) + + # Draw the player and the ghosts + player.draw(screen, counter) + blinky.draw(screen) + pinky.draw(screen) + inky.draw(screen) + clyde.draw(screen) + + + # Update the screen + pygame.display.flip() + + # Quit Pygame + pygame.quit() diff --git a/src/ghost.py b/src/ghost.py new file mode 100644 index 0000000..98b7deb --- /dev/null +++ b/src/ghost.py @@ -0,0 +1,82 @@ +import math +from util import get_sprites +from settings import settings +import map as Map + +dx = [1, 0, -1, 0] +dy = [0, 1, 0, -1] + +inv_dir = [2, 3, 0, 1] +sprite_sheet = [2, 0, 3, 1] + +class Ghost(): + def __init__(self,sprite_sheet, color, x, y): + self.x = x + self.y = y + self.sprite = get_sprites(sprite_sheet) + self.color = color + self.last_move = 3 + self.speed = 3 + + def in_bounds(self, pos): + (x, y) = pos + return (x >= 0) and (y >= 0) and (x < settings.width - 30) and (y < settings.height) + + def heuristic(self, next_pos, tx, ty): + 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): + is_dot = maze[y][x] == Map.D + is_big_dot = maze[y][x] == Map.BD + is_free = maze[y][x] == 0 + return (is_dot or is_free or is_big_dot) + + + # checks collision with pacman and obstacles returns false if there is a collision and true otherwise + def check_collision(self, nx, ny, gx, gy, maze): + direct_x = [1, 0, -1, 0, 1, 1, -1, -1] + direct_y = [0, 1, 0, -1, -1, 1, -1, 1] + + + for i in range(len(direct_x)): + px = nx + direct_x[i] * 14 + py = ny + direct_y[i] * 14 + x = px // gx + y = py // gy + if not self.in_bounds((px, py)) or not self.is_valid(maze, x, y): + return False + + return True + + + def get_next_move(self, pacman, maze): + + ret = len(dx) * [math.inf] + + forbidden = inv_dir[self.last_move] + + 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): + ret[i] = self.heuristic((nx, ny), pacman.x, pacman.y) + + min_idx = ret.index(min(ret)) + return min_idx + + + def move(self, maze, pacman): + min_idx = self.get_next_move(pacman, maze) + new_dx = dx[min_idx] * self.speed + new_dy = dy[min_idx] * self.speed + self.x += new_dx + self.y += new_dy + self.last_move = min_idx + + def draw(self, screen): + radius = 30 // 2 + pos = (self.x - radius , self.y - radius) + screen.blit(self.sprite[sprite_sheet[self.last_move]], pos) diff --git a/src/inky.py b/src/inky.py index 926a8d1..95eb80b 100644 --- a/src/inky.py +++ b/src/inky.py @@ -1,4 +1,4 @@ -from Ghost import Ghost +from ghost import Ghost class Inky(Ghost): def __init__(self, sprite_sheet, x, y): diff --git a/src/macpan.py b/src/macpan.py index a96a5fc..712fdde 100644 --- a/src/macpan.py +++ b/src/macpan.py @@ -1,5 +1,5 @@ -import Game +from game import Game if __name__ == "__main__": - game = Game.Game() - game.init() + game = Game() + game.run() diff --git a/src/pinky.py b/src/pinky.py index c8324bb..8b2bee1 100644 --- a/src/pinky.py +++ b/src/pinky.py @@ -1,8 +1,8 @@ from typing_extensions import override -from Direction import DIRECTION +from direction import DIRECTION from settings import settings import math -from Ghost import Ghost +from ghost import Ghost class Pinky(Ghost): def __init__(self, sprite_sheet, x, y): @@ -10,7 +10,6 @@ class Pinky(Ghost): def get_four_tiles_ahead_of_pacman(self, pacman): - print("Before", pacman.x, pacman.y) if pacman.direction == DIRECTION.UP: new_target = (pacman.x - 30 * 4, pacman.y - 30 * 4) if self.in_bounds(new_target): @@ -55,7 +54,6 @@ class Pinky(Ghost): forbidden = 1 new_target = self.get_four_tiles_ahead_of_pacman(target) - print("After: ", new_target) for i in range(len(dx)): if i != forbidden: diff --git a/src/player.py b/src/player.py new file mode 100644 index 0000000..34dc4a4 --- /dev/null +++ b/src/player.py @@ -0,0 +1,55 @@ +from typing import List +from direction import DIRECTION +import map as Map +from util import get_sprites +import pygame + + +class Player(): + def __init__(self, sprite_sheet): + self.x = 30 * 17 - 15 + self.y = 30 * 25 - 15 + self.sprite = get_sprites(sprite_sheet) + self.speed = 6 + self.direction = DIRECTION.LEFT + + # checks if the current position of pacman is either a dot, big dot or free + def is_valid(self,maze, x, y): + is_dot = maze.maze[y][x] == Map.D + is_big_dot = maze.maze[y][x] == Map.BD + is_free = maze.maze[y][x] == 0 + if is_dot or is_big_dot: + maze.maze[y][x] = 0 + + return (is_dot or is_free or is_big_dot) + + + # 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): + direct_x = [1, 0, -1, 0, 1, 1, -1, -1] + direct_y = [0, 1, 0, -1, -1, 1, -1, 1] + + for i in range(len(direct_x)): + ddx = dx + ddy = dy + nx = (self.x + ddx) + direct_x[i] * 14 + ny = (self.y + ddy) + direct_y[i] * 14 + x = nx // tile_width + y = ny // tile_height + if not self.is_valid(maze, x, y): + return False + + return True + + def draw(self, screen, counter): + radius = 30 // 2 + pos = (self.x - radius , self.y - radius) + # pygame.draw.circle(screen, 'green', pos, radius) + if self.direction == DIRECTION.UP: + screen.blit(pygame.transform.rotate(self.sprite[counter // 5], 270), pos) + elif self.direction == DIRECTION.DOWN: + screen.blit(pygame.transform.rotate(self.sprite[counter // 5], 90), pos) + elif self.direction == DIRECTION.RIGHT: + screen.blit(pygame.transform.flip(self.sprite[counter // 5], True, False), pos) + elif self.direction == DIRECTION.LEFT: + screen.blit(self.sprite[counter // 5], pos) -- cgit v1.2.3