Added maze loading. /JL

This commit is contained in:
2025-04-17 21:40:49 +02:00
parent fdd3ce1255
commit 21870930ef
8 changed files with 158 additions and 37 deletions

View File

@@ -1,9 +1,5 @@
from enum import Enum, auto
class PillType(Enum):
NORMAL = 1
POWER = 2
class PlayerDirection(Enum):
DirectionRight = 0
DirectionLeft = 180
@@ -29,6 +25,8 @@ class Colors(Enum):
WHITE = (255, 255, 255)
RED = (255, 0, 0)
# add others as needed
def __getitem__(self):
return self.value
class GhostColor(Enum):
BLINKY = (255, 0, 0)

View File

@@ -1,5 +1,6 @@
from .enums import GhostColor, GhostMode, GhostBehavior
from .behaviors import path_toward # required if you want a fallback
from .ghost_behaviors import path_toward # required if you want a fallback
import pygame
class Ghost(pygame.sprite.Sprite):
def __init__(self, name, color_enum, behavior_enum, position, speed):

View File

@@ -8,7 +8,7 @@ class ActorPacman:
self.direction = PlayerDirection.DirectionRight
self.speed = 3
self.x, self.y = center
self.radius = 100
self.radius = 10
self.mouth_angle_deg = 45
self.min_mouth_deg = 5
self.max_mouth_deg = 45
@@ -42,7 +42,7 @@ class ActorPacman:
def draw(self):
mouth_angle = math.radians(self.mouth_angle_deg)
center = (self.x, self.y)
rotation_offset = math.radians(self.direction, 0)
rotation_offset = math.radians(self.direction.value)
start_angle = mouth_angle / 2 + rotation_offset
end_angle = 2 * math.pi - mouth_angle / 2 + rotation_offset
points = [center]
@@ -52,7 +52,7 @@ class ActorPacman:
y = center[1] + self.radius * math.sin(angle)
points.append((x, y))
angle += math.radians(1)
pygame.draw.polygon(self.screen, Colors.Yellow, points)
pygame.draw.polygon(self.screen, Colors.Yellow.value, points)
def move_right(self):
pass

View File

@@ -23,7 +23,7 @@ class PivotWall:
(x + dx - dy * self.thickness / self.length, y + dy + dx * self.thickness / self.length),
]
pygame.draw.polygon(self.screen, Colors.Cyan, points)
pygame.draw.polygon(self.screen, Colors.Cyan.value, points)
def rotate(self, delta_angle):
self.angle = (self.angle + delta_angle) % 360
@@ -42,15 +42,15 @@ class GhostHome:
r = self.rect
t = self.wall_thickness
pygame.draw.rect(self.screen, Colors.Magenta, (r.left, r.top + t, t, r.height -t))
pygame.draw.rect(self.screen, Colors.Magenta, (r.right - t, r.top + t, t, r.height -t))
pygame.draw.rect(self.screen, Colors.Magenta, (r.left, r.bottom - t, r.width, t))
pygame.draw.rect(self.screen, Colors.Magenta.value, (r.left, r.top + t, t, r.height -t))
pygame.draw.rect(self.screen, Colors.Magenta.value, (r.right - t, r.top + t, t, r.height -t))
pygame.draw.rect(self.screen, Colors.Magenta.value, (r.left, r.bottom - t, r.width, t))
gap = 40
gap_x1 = r.centerx - gap // 2
gap_x2 = r.centerx + gap // 2
pygame.draw.rect(self.screen, Colors.Magenta, (r.left, r.top, gap_x1 - r.left, t))
pygame.draw.rect(self.screen, Colors.Magenta, (gap_x2, r.top, r.right - gap_x2, t))
pygame.draw.rect(self.screen, Colors.Magenta.value, (r.left, r.top, gap_x1 - r.left, t))
pygame.draw.rect(self.screen, Colors.Magenta.value, (gap_x2, r.top, r.right - gap_x2, t))
class Labyrinth:
def __init__(self, screen, width, height, wall_thickness=20):
@@ -72,15 +72,15 @@ class Labyrinth:
mid_x = self.width // 2
mid_y = self.height // 2
pygame.draw.rect(self.screen, Colors.Blue, (0, 0, mid_x - 50, w))
pygame.draw.rect(self.screen, Colors.Blue, (mid_x + 50, self.width - (mid_x + 50), w))
pygame.draw.rect(self.screen, Colors.Blue, (0, self.height - w, mid_x - 50, w))
pygame.draw.rect(self.screen, Colors.Blue, (mid_x + 50, self.height - w, self.width - (mid_x + 50), w))
pygame.draw.rect(self.screen, Colors.Blue.value, (0, 0, mid_x - 50, w))
pygame.draw.rect(self.screen, Colors.Blue.value, (mid_x + 50, 0, self.width - (mid_x + 50), w))
pygame.draw.rect(self.screen, Colors.Blue.value, (0, self.height - w, mid_x - 50, w))
pygame.draw.rect(self.screen, Colors.Blue.value, (mid_x + 50, self.height - w, self.width - (mid_x + 50), w))
pygame.draw.rect(self.screen, Colors.Blue, (0, 0, w, mid_y -50))
pygame.draw.rect(self.screen, Colors.Blue, (0, mid_y + 50, w, self.height - (mid_y + 50)))
pygame.draw.rect(self.screen, Colors.Blue, (self.width - w, 0, w, mid_y - 50))
pygame.draw.rect(self.screen, Colors.Blue, (self.width - w, mid_y + 50, w, self.height - (mid_y + 50)))
pygame.draw.rect(self.screen, Colors.Blue.value, (0, 0, w, mid_y -50))
pygame.draw.rect(self.screen, Colors.Blue.value, (0, mid_y + 50, w, self.height - (mid_y + 50)))
pygame.draw.rect(self.screen, Colors.Blue.value, (self.width - w, 0, w, mid_y - 50))
pygame.draw.rect(self.screen, Colors.Blue.value, (self.width - w, mid_y + 50, w, self.height - (mid_y + 50)))
for pivot in self.pivot_walls:
pivot.draw()

85
maze.py Normal file
View File

@@ -0,0 +1,85 @@
import pygame
TILE_SIZE = 32
# Color definitions
COLOR_BG = (0, 0, 0)
COLOR_WALL = (0, 0, 255)
COLOR_DOT = (255, 255, 255)
COLOR_POWER = (255, 255, 255)
class Maze:
def __init__(self, file_path):
self.file_path = file_path
self.layout = []
self.dots = set()
self.power_pellets = set()
self.load_maze()
def load_maze(self):
with open(self.file_path, "r") as f:
self.layout = [line.strip() for line in f.readlines()]
self.rows = len(self.layout)
self.cols = len(self.layout[0])
self.width = self.cols * TILE_SIZE
self.height = self.rows * TILE_SIZE
# Track collectible positions
self.dots.clear()
self.power_pellets.clear()
for y, row in enumerate(self.layout):
for x, char in enumerate(row):
if char == ".":
self.dots.add((x, y))
elif char == "*":
self.power_pellets.add((x, y))
elif char == "P":
self.pacman_start = (x * TILE_SIZE + TILE_SIZE // 2, y * TILE_SIZE + TILE_SIZE // 2)
def draw(self, screen):
for y, row in enumerate(self.layout):
for x, char in enumerate(row):
rect = pygame.Rect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE)
if char == "W":
pygame.draw.rect(screen, COLOR_WALL, rect)
# Draw dots
for (x, y) in self.dots:
center = (x * TILE_SIZE + TILE_SIZE // 2, y * TILE_SIZE + TILE_SIZE // 2)
pygame.draw.circle(screen, COLOR_DOT, center, 2)
# Draw power pellets
for (x, y) in self.power_pellets:
center = (x * TILE_SIZE + TILE_SIZE // 2, y * TILE_SIZE + TILE_SIZE // 2)
pygame.draw.circle(screen, COLOR_POWER, center, 5)
def tile_at(self, x, y):
"""Return the tile character at a specific (x, y) tile coordinate."""
if 0 <= y < self.rows and 0 <= x < self.cols:
return self.layout[y][x]
return " " # Treat out-of-bounds as path
def is_wall(self, x, y):
return self.tile_at(x, y) == "W"
def collect_dot(self, x, y):
"""Mark a dot as collected. Return True if there was a dot or power pellet."""
pos = (x, y)
if pos in self.dots:
self.dots.remove(pos)
return "dot"
elif pos in self.power_pellets:
self.power_pellets.remove(pos)
return "power"
return None
def reset_collectibles(self):
"""Reloads only dot/pellet positions from the layout."""
self.load_maze()
def pixel_to_tile(self, px, py):
"""Convert pixel coordinates to tile (grid) coordinates."""
return px // TILE_SIZE, py // TILE_SIZE
def tile_to_pixel(self, tx, ty):
"""Convert tile (grid) coordinates to top-left pixel position."""
return tx * TILE_SIZE, ty * TILE_SIZE

29
maze/pacman_maze.txt Normal file
View File

@@ -0,0 +1,29 @@
WWWWWWWWWWWWWWWWWWWWWWWWWWWWW
W.............W.............W
W.WWWWW.WWWWW.W.WWWWW.WWWWW.W
W*W W.W W.W.W W.W W*W
W.WWWWW.WWWWW.W.WWWWW.WWWWW.W
W...........................W
W.WWWWW.W.WWWWWWWWW.W.WWWWW.W
W.WWWWW.W.WWWWWWWWW.W.WWWWW.W
W.......W.....W.....W.......W
WWWWWWW.WWWWW.W.WWWWW.WWWWWWW
W W.WWWWW.W.WWWWW.W W
W W...............W W
WWWWWWW.W.WWW---WWW.W.WWWWWWW
........W.W W.W........
WWWWWWW.W.W W.W.WWWWWWW
W W.W.W W.W.W W
W W.W.WWWWWWWWW.W.W W
WWWWWWW.......P.......WWWWWWW
W.......WWWWWWWWWWWWW.......W
W.WWWWW.W W...W W.WWWWW.W
W*WWWWW.WWWWW.W.WWWWW.WWWWW*W
W...WW........W........WW...W
WWW.WW.WW.WWW...WWW.WW.WW.WWW
WWW.WW.WW.WWWWWWWWW.WW.WW.WWW
W......WW.....W.....WW......W
W.WWWWWWWWWWW.W.WWWWWWWWWWW.W
W.WWWWWWWWWWW.W.WWWWWWWWWWW.W
W...........................W
WWWWWWWWWWWWWWWWWWWWWWWWWWWWW

34
pman.py
View File

@@ -1,11 +1,13 @@
import pygame
from actors.enums import Colors, PlayerDirection
from actors.enums import Colors, PlayerDirection, PillType
from actors.pacman import ActorPacman
from labyrinth import Labyrinth
from actors.ghosts import Blinky, Pinky, Inky, Clyde # adjust import path as needed
from actors.ghost import Blinky, Pinky, Inky, Clyde # adjust import path as needed
from actors.ghost_mode_controller import GhostModeController
from scoreboard import Scoreboard
from maze import Maze
__version__ = "0.2.1"
__version__ = "0.2.3"
def spawn_ghosts(center_position):
@@ -37,7 +39,7 @@ def place_pills(maze, spacing=16):
for x in range(width):
if maze[y][x] == 0: # assuming 0 is path
if x % spacing == 0 and y % spacing == 0:
pills.add(NormalPill(x * spacing + spacing // 2, y * spacing + spacing // 2))
pills.add(PillType.PillTypeRegular(x * spacing + spacing // 2, y * spacing + spacing // 2))
# Power pills in 4 corners
corners = [
@@ -47,26 +49,29 @@ def place_pills(maze, spacing=16):
(height - 2, width - 2)
]
for cy, cx in corners:
pills.add(PowerPill(cx * spacing + spacing // 2, cy * spacing + spacing // 2))
pills.add(PillType.PillTypePower(cx * spacing + spacing // 2, cy * spacing + spacing // 2))
return pills
def main() -> None:
pygame.init()
screen_width, screen_height = 800, 800
screen_width, screen_height = (32*29), (32*30)
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("Pac-Man " + __version__)
scoreboard = Scoreboard()
labyrinth = Labyrinth(screen, width=screen_width, height=screen_height)
player = ActorPacman(screen, center=(200, 200))
ghost_home_center = (maze_width // 2, maze_height // 2)
#labyrinth = Labyrinth(screen, width=screen_width, height=screen_height)
maze = Maze("maze/pacman_maze.txt")
player = ActorPacman(screen, center=maze.pacman_start)
ghost_mode_controller = GhostModeController()
ghost_home_center = (screen_width // 2, screen_height // 2)
ghosts = spawn_ghosts(ghost_home_center)
clock = pygame.time.Clock()
running = True
while running:
screen.fill(Colors.Black)
screen.fill(Colors.Black.value)
for event in pygame.event.get():
match event.type:
@@ -83,7 +88,8 @@ def main() -> None:
case pygame.K_DOWN:
player.direction = PlayerDirection.DirectionDown
case pygame.JOYHATMOTION:
hat_x, hat_y =event.value
print("Hat has been pressed.")
hat_x, hat_y = event.value
if hat_x == 1:
player.direction = PlayerDirection.DirectionRight
elif hat_x == -1:
@@ -93,7 +99,9 @@ def main() -> None:
elif hat_y == -1:
player.direction = PlayerDirection.DirectionDown
labyrinth.draw()
#labyrinth.draw()
# In your main game loop:
maze.draw(screen)
player.animate()
player.draw()
ghost_mode_controller.update()
@@ -101,7 +109,7 @@ def main() -> None:
for ghost in ghosts:
ghost.set_mode(current_mode)
ghost.update(maze, pacman)
#ghost.update(maze, pacman)
ghosts.draw(screen)
scoreboard.draw(screen)

View File

@@ -1,6 +1,6 @@
import pygame
import os
from enums import Color
from actors.enums import Colors
class Scoreboard:
def __init__(self, font_size=24, highscore_file="highscore.txt"):
@@ -9,7 +9,7 @@ class Scoreboard:
self.highscore = self.load_highscore()
self.font = pygame.font.Font(None, font_size)
self.color = Color.WHITE.value
self.color = Colors.WHITE.value
self.score_pos = (10, 10)
self.highscore_pos = (10, 40)