import pygame import random import math # Constants WIDTH = 560 HEIGHT = 620 CELL_SIZE = 20 GRID_WIDTH = 28 GRID_HEIGHT = 31 FPS = 60 # Colors BLACK = (0, 0, 0) WHITE = (255, 255, 255) BLUE = (0, 0, 255) YELLOW = (255, 255, 0) RED = (255, 0, 0) PINK = (255, 192, 203) CYAN = (0, 255, 255) ORANGE = (255, 165, 0) # Initialize Pygame pygame.init() screen = pygame.display.set_mode((WIDTH, HEIGHT)) clock = pygame.time.Clock() class PacMan(pygame.sprite.Sprite): def __init__(self): super().__init__() self.original_image = pygame.Surface((CELL_SIZE, CELL_SIZE), pygame.SRCALPHA) pygame.draw.circle(self.original_image, YELLOW, (CELL_SIZE // 2, CELL_SIZE // 2), CELL_SIZE // 2) self.image = self.original_image.copy() self.rect = self.image.get_rect() self.rect.center = (CELL_SIZE * 14 + CELL_SIZE // 2, CELL_SIZE * 23 + CELL_SIZE // 2) self.direction = (0, 0) self.speed = 2 self.animation_timer = 0 self.animation_interval = FPS // 10 self.mouth_angle = 0 self.mouth_speed = 10 self.opening = False self.opening_angle = 0 def update(self): new_pos = (self.rect.centerx + self.direction[0] * self.speed, self.rect.centery + self.direction[1] * self.speed) if not any(wall.rect.collidepoint(new_pos) for wall in game.walls): self.rect.center = new_pos if self.rect.left < 0: self.rect.right = WIDTH elif self.rect.right > WIDTH: self.rect.left = 0 self.rect.clamp_ip(pygame.Rect(0, 0, WIDTH, HEIGHT)) self.animate_mouth() def change_direction(self, direction): self.direction = direction def animate_mouth(self): self.animation_timer += 1 if self.animation_timer >= self.animation_interval: self.animation_timer = 0 self.mouth_angle += self.mouth_speed if self.mouth_angle > 45 or self.mouth_angle < 0: self.mouth_speed = -self.mouth_speed self.mouth_angle = max(0, min(45, self.mouth_angle)) self.image = self.original_image.copy() if self.direction == (0, 0): return else: center = (CELL_SIZE // 2, CELL_SIZE // 2) if self.direction == (-1, 0): # Left start_angle = math.radians(180 + self.mouth_angle) end_angle = math.radians(360 - self.mouth_angle) elif self.direction == (1, 0): # Right start_angle = math.radians(self.mouth_angle) end_angle = math.radians(360 - self.mouth_angle) elif self.direction == (0, -1): # Up start_angle = math.radians(270 + self.mouth_angle) end_angle = math.radians(270 - self.mouth_angle) else: # Down start_angle = math.radians(90 + self.mouth_angle) end_angle = math.radians(90 - self.mouth_angle) if self.opening: self.opening_angle += 1 if self.opening_angle > 45: self.opening = False else: self.opening_angle -= 1 if self.opening_angle < -45: self.opening = True pygame.draw.arc(self.image, BLACK, (0, 0, CELL_SIZE, CELL_SIZE), start_angle, end_angle, 2) pygame.draw.circle(self.image, BLACK, center, CELL_SIZE // 2, 2) if self.opening: pygame.draw.arc(self.image, BLACK, (0, 0, CELL_SIZE, CELL_SIZE), math.radians(90 + self.opening_angle), math.radians(90 - self.opening_angle), 2) class Ghost(pygame.sprite.Sprite): def __init__(self, color, pos): super().__init__() self.image = pygame.Surface((CELL_SIZE, CELL_SIZE), pygame.SRCALPHA) self.color = color self.rect = self.image.get_rect() self.rect.center = pos self.direction = random.choice([(0, -1), (0, 1), (-1, 0), (1, 0)]) self.speed = 1 self.scared = False self.scared_timer = 0 self.spawn_pos = pos self.original_color = color self.draw_ghost(self.color, False) def draw_ghost(self, color, scared=False): # Body body_surface = pygame.Surface((CELL_SIZE, CELL_SIZE), pygame.SRCALPHA) pygame.draw.ellipse(body_surface, color, [0, 0, CELL_SIZE, CELL_SIZE - CELL_SIZE//3]) pygame.draw.rect(body_surface, color, [0, CELL_SIZE//2, CELL_SIZE, CELL_SIZE//2]) # Legs leg_width = CELL_SIZE // 5 for i in range(5): pygame.draw.polygon(body_surface, color, [ (i * leg_width, CELL_SIZE), (i * leg_width + leg_width//2, CELL_SIZE - (i % 2) * (CELL_SIZE//4)), (i * leg_width + leg_width, CELL_SIZE) ]) # Eyes eye_radius = CELL_SIZE // 6 eye_x = CELL_SIZE // 3 eye_y = CELL_SIZE // 4 pygame.draw.ellipse(body_surface, WHITE, (eye_x - eye_radius//2, eye_y - eye_radius, eye_radius * 2, eye_radius * 2)) pygame.draw.ellipse(body_surface, WHITE, (CELL_SIZE - eye_x - eye_radius//2, eye_y - eye_radius, eye_radius * 2, eye_radius * 2)) # Pupils - scared look pupil_radius = eye_radius // 2 pupil_offset_y = eye_radius // 2 if scared else 0 pupil_offset_x = 0 if scared else pupil_radius // 2 pygame.draw.circle(body_surface, BLACK, (eye_x, eye_y - pupil_offset_y), pupil_radius) pygame.draw.circle(body_surface, BLACK, (CELL_SIZE - eye_x, eye_y - pupil_offset_y), pupil_radius) self.image.blit(body_surface, (0, 0)) def update(self): if self.scared: self.scared_timer += 1 if self.scared_timer >= FPS * 5: self.scared = False self.scared_timer = 0 self.draw_ghost(self.original_color) new_pos = (self.rect.centerx + self.direction[0] * self.speed, self.rect.centery + self.direction[1] * self.speed) if any(wall.rect.collidepoint(new_pos) for wall in game.walls): opposite_direction = (-self.direction[0], -self.direction[1]) available_directions = [(0, -1), (0, 1), (-1, 0), (1, 0)] available_directions.remove(opposite_direction) self.direction = random.choice(available_directions) else: self.rect.center = new_pos self.rect.clamp_ip(pygame.Rect(0, 0, WIDTH, HEIGHT)) def set_scared(self): if not self.scared: self.scared = True self.draw_ghost(BLUE, True) # Draw as scared and blue self.direction = (-self.direction[0], -self.direction[1]) # Reverse direction def respawn(self): self.rect.center = self.spawn_pos self.scared = False self.scared_timer = 0 self.draw_ghost(self.original_color, False) # Pellet class class Pellet(pygame.sprite.Sprite): def __init__(self, pos): super().__init__() self.image = pygame.Surface((CELL_SIZE // 4, CELL_SIZE // 4)) self.image.fill(WHITE) self.rect = self.image.get_rect() self.rect.center = pos # Power Pellet class class PowerPellet(pygame.sprite.Sprite): def __init__(self, pos): super().__init__() self.image = pygame.Surface((CELL_SIZE // 2, CELL_SIZE // 2)) self.image.fill(WHITE) self.rect = self.image.get_rect() self.rect.center = pos # Wall class class Wall(pygame.sprite.Sprite): def __init__(self, pos, size): super().__init__() self.image = pygame.Surface(size) self.image.fill(BLUE) self.rect = self.image.get_rect() self.rect.topleft = pos # Game class class Game: def __init__(self): self.pac_man = PacMan() self.ghosts = pygame.sprite.Group() self.pellets = pygame.sprite.Group() self.power_pellets = pygame.sprite.Group() self.walls = pygame.sprite.Group() self.all_sprites = pygame.sprite.Group(self.pac_man) self.score = 0 self.game_over = False self.generate_map() def generate_map(self): # Define the map layout map_layout = [ "############################", "#............##............#", "#.####.#####.##.#####.####.#", "#o####.#####.##.#####.####o#", "#.####.#####.##.#####.####.#", "#..........................#", "#.####.##.########.##.####.#", "#.####.##.########.##.####.#", "#......##....##....##......#", "######.#####.##.#####.######", "######.#####.##.#####.######", "######.## ##.######", "######.## # # ##.######", "######.## # # ##.######", " . # # . ", "######.## # # ##.######", "######.## ######## ##.######", "######.## ##.######", "######.## ######## ##.######", "######.## ######## ##.######", "#............##............#", "#.####.#####.##.#####.####.#", "#.####.#####.##.#####.####.#", "#o..##................##..o#", "###.##.##.########.##.##.###", "###.##.##.########.##.##.###", "#......##....##....##......#", "#.##########.##.##########.#", "#.##########.##.##########.#", "#..........................#", "############################" ] # Create walls, pellets, and power pellets based on the map layout for i, row in enumerate(map_layout): for j, cell in enumerate(row): if cell == "#": self.walls.add(Wall((j * CELL_SIZE, i * CELL_SIZE), (CELL_SIZE, CELL_SIZE))) elif cell == ".": pellet = Pellet((j * CELL_SIZE + CELL_SIZE // 2, i * CELL_SIZE + CELL_SIZE // 2)) self.pellets.add(pellet) self.all_sprites.add(pellet) elif cell == "o": power_pellet = PowerPellet((j * CELL_SIZE + CELL_SIZE // 2, i * CELL_SIZE + CELL_SIZE // 2)) self.power_pellets.add(power_pellet) self.all_sprites.add(power_pellet) # Create ghosts ghost_colors = [RED, PINK, CYAN, ORANGE] ghost_positions = [ (CELL_SIZE * 12 + CELL_SIZE // 2, CELL_SIZE * 14 + CELL_SIZE // 2), (CELL_SIZE * 15 + CELL_SIZE // 2, CELL_SIZE * 14 + CELL_SIZE // 2), (CELL_SIZE * 12 + CELL_SIZE // 2, CELL_SIZE * 15 + CELL_SIZE // 2), (CELL_SIZE * 15 + CELL_SIZE // 2, CELL_SIZE * 15 + CELL_SIZE // 2) ] for color, pos in zip(ghost_colors, ghost_positions): ghost = Ghost(color, pos) self.ghosts.add(ghost) self.all_sprites.add(ghost) self.all_sprites.add(self.walls) def update(self): self.all_sprites.update() pellet_collisions = pygame.sprite.spritecollide(self.pac_man, self.pellets, True) self.score += len(pellet_collisions) power_pellet_collisions = pygame.sprite.spritecollide(self.pac_man, self.power_pellets, True) if power_pellet_collisions: for ghost in self.ghosts: ghost.set_scared() ghost_collisions = pygame.sprite.spritecollide(self.pac_man, self.ghosts, False) for ghost in ghost_collisions: if ghost.scared: ghost.respawn() self.score += 200 else: self.game_over = True if len(self.pellets) == 0: self.game_over = True def draw(self): screen.fill(BLACK) self.all_sprites.draw(screen) score_text = pygame.font.SysFont(None, 36).render(f"Score: {self.score}", True, WHITE) screen.blit(score_text, (10, HEIGHT - 30)) pygame.display.flip() def run(self): while not self.game_over: for event in pygame.event.get(): if event.type == pygame.QUIT: self.game_over = True elif event.type == pygame.KEYDOWN: if event.key == pygame.K_LEFT: self.pac_man.change_direction((-1, 0)) elif event.key == pygame.K_RIGHT: self.pac_man.change_direction((1, 0)) elif event.key == pygame.K_UP: self.pac_man.change_direction((0, -1)) elif event.key == pygame.K_DOWN: self.pac_man.change_direction((0, 1)) self.update() self.draw() clock.tick(FPS) pygame.quit() # Run the game if __name__ == "__main__": game = Game() game.run()