391 lines
13 KiB
Python
391 lines
13 KiB
Python
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)
|