import sys import pygame as pg from pygame import mixer from Blinky import Blinky from Clyde import Clyde from Inky import Inky from Clyde import Clyde from DrawType import DrawType from Maze import Maze from Pinky import Pinky from Player import Player from PointGrid import PointGrid from Vec import Vec import time import os # Variables screen_width: int = 780 screen_height: int = 780 grid_cell_size: int = 26 startTime = time.time() relativeStartTime = time.time() delta_Time_Sec = 0 highscore = 0 clock = pg.time.Clock() pointsToWin = 0 def auto_place_player(p: Player, m: Maze): global default_pos_player x = 15 for y in range(0, 29): if m.is_free(Vec(x, y)): p.position = Vec(x * grid_cell_size, y * grid_cell_size) default_pos_player = Vec(x * grid_cell_size, y * grid_cell_size) # Init Pygame pg.init() screen = pg.display.set_mode((screen_width, screen_height), pg.RESIZABLE + pg.SCALED, vsync=1) overlayFont = pg.font.SysFont("Comic Sans", 22) finishFont = pg.font.SysFont("Comic Sans", 70) restartFont = pg.font.SysFont("Comic Sans", 22) pg.display.set_icon(pg.image.load("/PacMan.png")) pg.display.set_caption("PacMan") pause = False mixer.init() mixer.music.load("/pacman-background-music.wav") mixer.music.queue("/pacman-background-music.wav", loops=100) mixer.music.set_volume(0.05) mixer.music.play() click_sound = pg.mixer.Sound("/click.wav") click_sound.set_volume(0.05) # Init Player default_pos_player: Vec = None player = Player(Vec(0, 0), Vec(grid_cell_size / 2 - 1, grid_cell_size / 2 - 1), 2, grid_cell_size) player.velocity = Vec(0, 0) # Generate Maze maze = Maze(grid_cell_size) maze.read_file("../Game/maze.pac") auto_place_player(player, maze) # Init Points points = PointGrid(grid_cell_size, screen_width, screen_height, maze, 3) # Ghosts last_time_ghosts_afraid = 0 # Blinky blinky = Blinky(Vec(12 * grid_cell_size, 15 * grid_cell_size), Vec(grid_cell_size / 2 - 1, grid_cell_size / 2 - 1), screen_width, grid_cell_size, player, maze.maze) blinky_start_delay = 2 # Pinky pinky = Pinky(Vec(13 * grid_cell_size, 15 * grid_cell_size), Vec(grid_cell_size / 2 - 1, grid_cell_size / 2 - 1), screen_width, grid_cell_size, player, maze.maze) pinky_start_delay = 5.5 # Inky inky = Inky(Vec(14 * grid_cell_size, 15 * grid_cell_size), Vec(grid_cell_size / 2 - 1, grid_cell_size / 2 - 1), screen_width, grid_cell_size, player, maze.maze, blinky.position, screen) inky_start_delay = 9 # Clyde clyde = Clyde(Vec(15 * grid_cell_size, 15 * grid_cell_size), Vec(grid_cell_size / 2 - 1, grid_cell_size / 2 - 1), screen_width, grid_cell_size, player, maze.maze) clyde_start_delay = 12.5 # Images player_image = pg.image.load("/PacMan.png") player_image = pg.transform.scale(player_image, (grid_cell_size, grid_cell_size)) player_image2 = pg.image.load("/PacMan2.png") player_image2 = pg.transform.scale(player_image2, (grid_cell_size, grid_cell_size)) ghost_afraid_image = pg.image.load("/GhostAfraid.png") ghost_afraid_image = pg.transform.scale(ghost_afraid_image, (grid_cell_size, grid_cell_size)) blinky_image = pg.image.load("/Blinky.png") blinky_image = pg.transform.scale(blinky_image, (grid_cell_size, grid_cell_size)) pinky_image = pg.image.load("/Pinky.png") pinky_image = pg.transform.scale(pinky_image, (grid_cell_size, grid_cell_size)) inky_image = pg.image.load("/Inky.png") inky_image = pg.transform.scale(inky_image, (grid_cell_size, grid_cell_size)) clyde_image = pg.image.load("/Clyde.png") clyde_image = pg.transform.scale(clyde_image, (grid_cell_size, grid_cell_size)) # Function called when game should close def on_game_exit(): pg.quit() os.system("python3 ../Start/Start.py") # function to clear the screen def clear_screen(): screen.fill((255, 255, 255)) def check_points_possible_to_eat(): global last_time_ghosts_afraid global pause global finishFont check = Vec(player.position.x + grid_cell_size / 2, player.position.y + grid_cell_size / 2) surrounding_point = points.get_surrounding_points(check) for point in surrounding_point: if check.distance(point.position) < 3: if not point.eaten: pg.mixer.Sound.play(click_sound) if point.big: player.score += 50 last_time_ghosts_afraid = time.time() else: player.score += 10 point.eat() # Highscore Overlay def draw_highscore(): if os.path.getsize("/highscore.pac") == 0: text = "Schnellste gewonnene Runde: Keine vorhanden :P" else: with open("/highscore.pac", "r") as myTest: content = myTest.read() sec = int(content) % 60 min = int(content) / 60 text = "Schnellste gewonnene Runde: " + str(int(min)) + " Minuten " + str(sec) + " Sekunden" highscore_screen = restartFont.render(text, True, (0, 0, 0)) highscore_rect = highscore_screen.get_rect() highscore_rect.center = (screen_width // 2, screen_height // 2 + 80) screen.blit(highscore_screen, highscore_rect) # Aktueller Score Overlay def draw_currentscore(): global delta_Time_Sec sec = delta_Time_Sec % 60 min = int(delta_Time_Sec / 60) currentscore_screen = restartFont.render("Aktuelle Runde: " + str(min) + " Minuten " + str(sec) + " Sekunden", True, (0, 0, 0)) currentscore_rect = currentscore_screen.get_rect() currentscore_rect.center = (screen_width // 2, screen_height // 2 + 110) screen.blit(currentscore_screen, currentscore_rect) # Punkte Overlay def draw_overlayPoints(): global overlayFont pointSurface = overlayFont.render("Punkte: " + str(player.score), True, (0, 0, 0)) textrect = pointSurface.get_rect() textrect.center = (screen_width // 2, screen_height - 30) screen.blit(pointSurface, textrect) hp_surface = overlayFont.render("Übrige Leben: " + str(player.hp - 1), True, (0, 0, 0)) hp_rect = hp_surface.get_rect() hp_rect.center = (screen_width, screen_height - 30) hp_rect.right = (screen_width - 10) screen.blit(hp_surface, hp_rect) # Timer Overlay def draw_overlayTime(): global overlayFont global delta_Time_Sec global delta_Time_Minute delta_Time_Sec = int(time.time() - startTime) rest = delta_Time_Sec % 60 delta_Time_Minute = delta_Time_Sec - rest timeSurface = overlayFont.render(str(delta_Time_Minute // 60) + " min " + str(rest) + " sek", True, (0, 0, 0)) timerect = timeSurface.get_rect() timerect.center = (0, screen_height - 30) timerect.left = 10 screen.blit(timeSurface, timerect) def reset_positions(): player.position = default_pos_player.get_instance() blinky.set_position(blinky.default_pos.get_instance()) pinky.set_position(pinky.default_pos.get_instance()) inky.set_position(inky.default_pos.get_instance()) clyde.set_position(clyde.default_pos.get_instance()) def restart(): global pause global startTime global relativeStartTime global last_time_ghosts_afraid player.hp = 3 player.score = 0 startTime = time.time() relativeStartTime = time.time() reset_positions() blinky.stateChange = time.time() pinky.stateChange = time.time() inky.stateChange = time.time() clyde.stateChange = time.time() last_time_ghosts_afraid = 0 blinky.chase = True pinky.chase = True inky.chase = True clyde.chase = True for x in range(0, 30): for y in range(0, 30): points.points[x][y].eaten = maze.maze[x][y] != 0 pause = False def save_highscore(): global highscore global delta_Time_Sec if os.path.getsize("/highscore.pac") == 0: with open("/highscore.pac", "w") as overwrite: overwrite.write(str(delta_Time_Sec)) highscore = delta_Time_Sec else: with open("/highscore.pac", "r") as getScore: if delta_Time_Sec < int(getScore.read()): with open("/highscore.pac", "w") as overwrite: overwrite.write(str(delta_Time_Sec)) highscore = delta_Time_Sec def check_ghost_collisions(): global relativeStartTime global pause global finishFont global restartFont global last_time_ghosts_afraid if (blinky.position.distance(player.position) < 20 or pinky.position.distance( player.position) < 20 or inky.position.distance(player.position) < 20 or clyde.position.distance( player.position) < 20) \ and time.time() - player.last_time_hit > 1 and time.time() - last_time_ghosts_afraid > 8: relativeStartTime = time.time() player.last_time_hit = time.time() player.hp -= 1 reset_positions() def calc_points_to_win(): global maze count = 0 for i in maze.maze: for j in i: if j == 0: count += 1 count -= 4 count *= 10 count += 4 * 50 return count pointsToWin = calc_points_to_win() while True: for e in pg.event.get(): if e.type == pg.QUIT: on_game_exit() break # Clear the screen clear_screen() maze.draw(screen, (200, 200, 200), (150, 150, 150)) # Draw the points points.draw(screen, (255, 100, 0), DrawType.circle) if not pause: # Player actions player.poll_keys(maze) player.move(maze) player.check_bounds_move(screen_width, screen_height) player.draw(screen, (252, 186, 3), DrawType.image, grid_cell_size, image=pg.transform.rotate(player_image if player.get_state() else player_image2, player.get_rotation())) check_points_possible_to_eat() draw_overlayPoints() draw_overlayTime() # Check Ghosts if time.time() - last_time_ghosts_afraid < 8: if time.time() - relativeStartTime > pinky_start_delay: pinky.idle() if time.time() - relativeStartTime > blinky_start_delay: blinky.idle() if time.time() - relativeStartTime > inky_start_delay: inky.idle() if time.time() - relativeStartTime > clyde_start_delay: clyde.idle() blinky.draw(screen, (0, 0, 0), DrawType.image, grid_cell_size, image=pg.transform.flip(ghost_afraid_image, blinky.is_mirrored(), False)) pinky.draw(screen, (0, 0, 0), DrawType.image, grid_cell_size, image=pg.transform.flip(ghost_afraid_image, pinky.is_mirrored(), False)) inky.draw(screen, (0, 0, 0), DrawType.image, grid_cell_size, image=pg.transform.flip(ghost_afraid_image, inky.is_mirrored(), False)) clyde.draw(screen, (0, 0, 0), DrawType.image, grid_cell_size, image=pg.transform.flip(ghost_afraid_image, clyde.is_mirrored(), False)) else: if time.time() - relativeStartTime > blinky_start_delay: blinky.run() if time.time() - relativeStartTime > pinky_start_delay: pinky.run() if time.time() - relativeStartTime > inky_start_delay: inky.run() if time.time() - relativeStartTime > clyde_start_delay: clyde.run() blinky.draw(screen, (0, 0, 0), DrawType.image, grid_cell_size, image=pg.transform.flip(blinky_image, blinky.is_mirrored(), False)) pinky.draw(screen, (0, 0, 0), DrawType.image, grid_cell_size, image=pg.transform.flip(pinky_image, pinky.is_mirrored(), False)) inky.draw(screen, (0, 0, 0), DrawType.image, grid_cell_size, image=pg.transform.flip(inky_image, inky.is_mirrored(), False)) clyde.draw(screen, (0, 0, 0), DrawType.image, grid_cell_size, image=pg.transform.flip(clyde_image, clyde.is_mirrored(), False)) check_ghost_collisions() if player.score >= pointsToWin: save_highscore() win_screen = finishFont.render("Gewonnen!", True, (0, 0, 0)) win_rect = win_screen.get_rect() win_rect.center = (screen_width // 2, screen_height // 2) screen.blit(win_screen, win_rect) restart_screen = restartFont.render("Drücke 'R' um noch eine Runde zu spielen!", True, (0, 0, 0)) restart_rect = restart_screen.get_rect() restart_rect.center = (screen_width // 2, screen_height // 2 + 50) screen.blit(restart_screen, restart_rect) draw_highscore() draw_currentscore() keys = pg.key.get_pressed() pause = True if keys[pg.K_r]: restart() elif player.hp == 0: lose_screen = finishFont.render("Game Over!", True, (0, 0, 0)) lose_rect = lose_screen.get_rect() lose_rect.center = (screen_width // 2, screen_height // 2) screen.blit(lose_screen, lose_rect) restart_screen = restartFont.render("Drücke 'R' um es wieder zu versuchen!", True, (0, 0, 0)) restart_rect = restart_screen.get_rect() restart_rect.center = (screen_width // 2, screen_height // 2 + 50) screen.blit(restart_screen, restart_rect) draw_highscore() keys = pg.key.get_pressed() pause = True if keys[pg.K_r]: restart() # Update the display pg.display.flip() clock.tick(60)