pygame自動生成迷宮遊戲製作

我的迷宮遊戲小實作

最近在玩 Python,順便自己做了一個迷宮遊戲,用的是 Pygame。基本概念是這樣的:我畫一個格子地圖,每個格子都有牆,然後用程式隨機生成通路,玩家就要從左上角走到右下角。

程式裡我設定了畫面大小、格子數量和每格的尺寸,還有顏色設定:牆是黑色、路是白色、玩家是紅色、終點是綠色,完成遊戲會跳出黃色的「MISSION COMPLETE!」。

每個格子都是一個 Cell 類別物件,它有牆的資訊和是否被走過的標記。生成迷宮用的是 深度優先搜尋(DFS),簡單說就是從起點一路隨機走,遇到死路就回到上一格再試其他路,直到整個格子都走過。

玩家可以用方向鍵移動,但如果前面有牆就不能走。每次畫面更新,程式會重繪整個迷宮、玩家和終點。如果到達終點就顯示完成訊息。

這個小遊戲對我來說很好玩,也練到了程式邏輯、物件導向概念和 Pygame 畫圖的方法。下一步想試試加計時、計分,甚至做成自動解迷的功能。

這是我的程式碼:

import pygame
import sys
import random

SCREEN_WIDTH = 1000
SCREEN_HEIGHT = 750
FPS = 30

COLS, ROWS = 40, 30
CELL_SIZE = min(SCREEN_WIDTH // COLS, SCREEN_HEIGHT // ROWS)
PLAYER_SIZE = max(1, (CELL_SIZE * 2) // 3)

WALL_COLOR = (0, 0, 0)
PATH_COLOR = (255, 255, 255)
PLAYER_COLOR = (255, 0, 0)
GOAL_COLOR = (0, 255, 0)
WIN_TEXT_COLOR = (255, 255, 0)

class Cell:
def __init__(self, x, y, cell_size):
self.x, self.y = x, y
self.cell_size = cell_size
self.walls = {'top': True, 'right': True, 'bottom': True, 'left': True}
self.visited = False

def draw(self, screen):
x, y = self.x * self.cell_size, self.y * self.cell_size
line_thickness = max(1, self.cell_size // 15)
if self.walls['top']:
pygame.draw.line(screen, WALL_COLOR, (x, y), (x + self.cell_size, y), line_thickness)
if self.walls['right']:
pygame.draw.line(screen, WALL_COLOR, (x + self.cell_size, y), (x + self.cell_size, y + self.cell_size), line_thickness)
if self.walls['bottom']:
pygame.draw.line(screen, WALL_COLOR, (x + self.cell_size, y + self.cell_size), (x, y + self.cell_size), line_thickness)
if self.walls['left']:
pygame.draw.line(screen, WALL_COLOR, (x, y + self.cell_size), (x, y), line_thickness)

def remove_walls(current, next_cell):
dx = current.x - next_cell.x
if dx == 1:
current.walls['left'] = False
next_cell.walls['right'] = False
elif dx == -1:
current.walls['right'] = False
next_cell.walls['left'] = False
dy = current.y - next_cell.y
if dy == 1:
current.walls['top'] = False
next_cell.walls['bottom'] = False
elif dy == -1:
current.walls['bottom'] = False
next_cell.walls['top'] = False

def get_neighbors(cell, grid, COLS, ROWS):
neighbors = []
moves = [(0, -1), (1, 0), (0, 1), (-1, 0)]
for dx, dy in moves:
nx, ny = cell.x + dx, cell.y + dy
if 0 <= nx < COLS and 0 <= ny < ROWS and not grid[ny][nx].visited:
neighbors.append(grid[ny][nx])
return neighbors

def generate_maze(grid, COLS, ROWS):
stack = []
current_cell = grid[0][0]
current_cell.visited = True
stack.append(current_cell)

while stack:
current_cell = stack[-1]
neighbors = get_neighbors(current_cell, grid, COLS, ROWS)

if neighbors:
next_cell = random.choice(neighbors)
remove_walls(current_cell, next_cell)
next_cell.visited = True
stack.append(next_cell)
else:
stack.pop()

pygame.init()
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption(f"Maze Game")
clock = pygame.time.Clock()
font_large = pygame.font.Font(None, 100)

grid = [[Cell(x, y, CELL_SIZE) for x in range(COLS)] for y in range(ROWS)]
generate_maze(grid, COLS, ROWS)

grid_x, grid_y = 0, 0
game_won = False

running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
running = False
if not game_won and event.type == pygame.KEYDOWN:
px, py = grid_x, grid_y
if event.key == pygame.K_UP and not grid[py][px].walls['top']: py -= 1
elif event.key == pygame.K_DOWN and not grid[py][px].walls['bottom']: py += 1
elif event.key == pygame.K_LEFT and not grid[py][px].walls['left']: px -= 1
elif event.key == pygame.K_RIGHT and not grid[py][px].walls['right']: px += 1

if 0 <= px < COLS and 0 <= py < ROWS:
grid_x, grid_y = px, py
if grid_x == COLS - 1 and grid_y == ROWS - 1:
game_won = True

screen.fill(PATH_COLOR)
for row in grid:
for cell in row:
cell.draw(screen)

goal_rect = pygame.Rect((COLS - 1) * CELL_SIZE, (ROWS - 1) * CELL_SIZE, CELL_SIZE, CELL_SIZE)
pygame.draw.rect(screen, GOAL_COLOR, goal_rect)

player_size = PLAYER_SIZE
player_rect_x = grid_x * CELL_SIZE + (CELL_SIZE - player_size) // 2
player_rect_y = grid_y * CELL_SIZE + (CELL_SIZE - player_size) // 2
player_rect = pygame.Rect(player_rect_x, player_rect_y, player_size, player_size)
pygame.draw.rect(screen, PLAYER_COLOR, player_rect)
if game_won:
text = font_large.render("MISSION COMPLETE!", True, WIN_TEXT_COLOR)
text_rect = text.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2))
screen.blit(text, text_rect)

pygame.display.flip()
clock.tick(FPS)

pygame.quit()
sys.exit()

留言

  1. 實在太厲害了!而且文筆也描述得清晰分明,加上成熟的後設認知:清楚知道自己學到了什麼、接下來想挑戰什麼。

    回覆刪除

張貼留言

這個網誌中的熱門文章

平方的方法