用python的pygame写迷宫游戏

一、概述:

  项目目标和主要内容

1)迷宫游戏是非常经典的游戏,在该题中要求随机生成一个迷宫,并求解迷宫。

2)要求查找并理解迷宫生成的算法,并尝试用两种不同的算法来生成随机的迷宫。

3)要求迷宫游戏支持玩家走迷宫,和系统走迷宫路径两种模式。玩家走迷宫,通过键盘方向键控制,并在行走路径上留下痕迹;系统提示迷宫路径要求基于A*算法实现,输出玩家当前位置到迷宫出口的最优路径。设计交互友好的游戏图形界面。

  项目的主要功能

1)玩家模式:程序应该允许玩家通过键盘方向键在迷宫中移动。同时,玩家的行走路径应该在图形界面中实时显示出来。

2)系统模式:程序应该能够基于A*算法或其他寻路算法自动找出从入口到出口的最优路径。最优路径应该是步数最少的路径,如果有多个步数相同的路径,应该都能够输出。

3)交互友好的图形界面:程序应该具有一个能够清晰地显示出迷宫的图形界面,以便于玩家进行游戏

二、实现:

1.开始界面:

用户可以自定义行列,因为有奇数道墙、偶数条路,所以行列数必须为奇数

2.游戏界面:

上下左右键控制移动,空格显示提示路径,R隐藏提示

3.PRIM算法生成迷宫:

        现根据行列创建出二位数组matrix[][],每个元素都赋值为1,代表墙。将[1][1]赋值为0,作为第一个路点。加入新路点列表

        1)得到一个路点,隔一面墙寻找它周围点,依次加入备选路点列表,从表中随机选出一个墙点赋值为0代表新路点,加入新路点列表,移出备选点列表,同时打通此点与相邻的随机路点之间的墙,即将他们之间的点赋值为0。

        2)随机从新路点列表中选出一点,选出的新路点重复1)操作。

        3)一直重复到备选点列表为空,最后得到一个迷宫。

4.astar算法寻找路径

重复以下步骤,直到遍历到终点 End:

1)选取当前 open 列表中评价值 F 最小的节点,将这个节点称为 S;

2)将 S 从 open列表移除,然后添加 S 到 closed 列表中;

3)对于与 S 相邻的每一块可移动的相邻节点 T:如果 T 在 closed列表中,忽略;如果 T 不在 open 列表中,添加它然后计算它的 F值;如果 T 已经在 open 列表中,当我们从 S 到达 T时:检查是否能得到更小的 F 值,如果是,更新它的 F 值和它的前继(parent = S)。

5.DFS寻找路径

重复以下步骤,直到遍历到终点 End:

1)从起点开始,依次从上下左右四个方向走。

2)如果可以走通即是有路,就递归 1),如过走不通,就返回上一个分叉口,递归 1)且走其他方向。

3)当可以走通时,在迷宫列表中设下标记。如果走不通就撤回标记。

4)利用迷宫的标记渲染出路径。

5)到终点end即退出此程序。

三、设计

总体框架:

详细设计:

import heapq
import sys
import tkinter as tk
from tkinter.font import Font
import pygame
import tkinter.messagebox as tk1
import random
import time

root = tk.Tk()
root.title('迷宫')
root.geometry('250x340')
R = 0#行数
C = 0#列数
var = tk.IntVar()
label1=tk.Label(root,text='-迷宫-',width=10,font=('STzhongsong',30))
label1.pack()
label2=tk.Label(root,text='-选择难度-',width=10,font=('STzhongsong',20))
label2.pack()


#迷宫行列数
label3=tk.Label(root,text='行数',width=10,font=('STzhongsongl',20))
label3.place(x=85,y=96)
label4=tk.Label(root,text='列数',width=10,font=('STzhongsongl',20))
label4.place(x=85,y=136)
e1=tk.Entry(root,show='',width=5,bd=2,font=('Arial',15))
e1.place(x=65,y=100)
e2=tk.Entry(root,show='',width=5,bd=2,font=('Arial',15))
e2.place(x=65,y=140)

#开始游戏
def cul():
    try:
        R=int(eval(e1.get()))#得到行数
        C=int(eval(e2.get()))#得到列数
        ROWS = R
        COLUMNS = C
    except:
        ROWS = 31#默认行列,下同
        COLUMNS = 31
    root.destroy()  # 关闭起始框
    time_start = time.time()#记录开始时间
    to_be_selected_point = []#备选点列表
    roadwidth = 20#路宽墙宽
    is_visit = [[0 for i in range(COLUMNS)] for j in range(ROWS)]  # 访问过赋值1,反之赋值0。目前全都未访问,赋值为0
    random_select_point = []#备选点周围路点组成的随机点
    path_point_list = []#自动寻路时路点集合
    x = [0, 2, 0, -2]#寻点用到的列表
    y = [2, 0, -2, 0]
    px = [0, 1, 0, -1]
    py = [1, 0, -1, 0]
    image1 = pygame.image.load('D:/Python/迷宫/mlo1.jpg')
    image2 = pygame.image.load('D:/Python/迷宫/qiang.png')
    image3 = pygame.image.load('D:/Python/迷宫/qi1.jpg')

    #迷宫初始化
    def matrix_init(r, c):
        matrix = [[1 for i in range(c)] for j in range(r)]  # 墙是1,路是0
        matrix[1][1] = 0#坐标(1,1)定义为路
        return matrix

    #把点放入备选点
    def put_node_in_to_be_selected_point(node):
        for i in range(4):#上下左右隔一道墙寻点
            xx = node[0] + x[i]
            yy = node[1] + y[i]
            #不超出界限,不在备选点列表且是墙点
            if xx > 0 and xx < ROWS and yy > 0 and yy < COLUMNS and ([xx, yy] not in to_be_selected_point) and \
                    matrix[xx][
                        yy] == 1:
                to_be_selected_point.append([xx, yy])

    def be_selected_near_roadpoint(node):  # node点周围的路点
        random_select_point.clear()
        for i in range(4):#上下左右不隔墙寻点
            xx = node[0] + x[i]
            yy = node[1] + y[i]
            #不超出界限且是路点
            if xx > 0 and xx < ROWS and yy > 0 and yy < COLUMNS and matrix[xx][yy] == 0:
                random_select_point.append([xx, yy])
        random_point = random.randint(0, len(random_select_point) - 1)
        return random_select_point[random_point]#返回随机路点

    #输入当前坐标自动寻路
    def path_searching_dfs(pathx, pathy):
        path_point_list.append([pathx, pathy])  # 将初始点加入路点
        while True:
            if len(path_point_list) > 0:  # 如果有路点
                # print(11111111111111111111111111111111111111111111111111111111111111111111111)
                l = len(path_point_list) - 1
                n = path_point_list[l]  # 最后一个路点
                if n[0] == ROWS - 2 and n[1] == COLUMNS - 2:  # 如果第一个路点和最后一个路点重合
                    return
                for i in range(4):
                    xx = n[0] + px[i]
                    yy = n[1] + py[i]
                    if xx > 0 and xx < ROWS - 1 and yy > 0 and yy < COLUMNS - 1 and (
                            matrix[xx][yy] == 0 or matrix[xx][yy] == 3 or matrix[xx][yy] == 4) and is_visit[xx][
                        yy] == 0:  # 是路点或者终点并且没有被访问过
                        is_visit[xx][yy] = 1  # 成为访问过的点
                        matrix[n[0]][n[1]] = 2  # 记录访问过的路径
                        tmp = [xx, yy]  # 加入路点
                        path_point_list.append(tmp)
                        break
                    elif i == 3:  # 如果回退了
                        matrix[n[0]][n[1]] = 0  # 将路径撤回
                        path_point_list.pop()  # 撤回路点
            else:
                return

        # 计算曼哈顿距离
    def heuristic(a, b):
        return abs(a[0] - b[0]) + abs(a[1] - b[1])

    # A*算法寻路
    def path_searching_astar(start):
        end=(ROWS - 2, COLUMNS - 2)
        frontier = []
        heapq.heappush(frontier, (0, start))
        came_from = {}
        cost_so_far = {}
        came_from[start] = None
        cost_so_far[start] = 0
        while len(frontier) > 0:
            _,current = heapq.heappop(frontier)
            if current == end:
                break
            for next in [(0, -1), (0, 1), (-1, 0), (1, 0)]:  #上, 下,左, 右
                next = (current[0] + next[0], current[1] + next[1])
                if next[0] > 0 and next[0] <=COLUMNS and next[1] > 0 and next[1] <=ROWS and \
                        matrix[next[1]][next[0]] != 1:
                    new_cost = cost_so_far[current] + 1
                    if next not in cost_so_far or new_cost < cost_so_far[next]:
                        cost_so_far[next] = new_cost
                        priority = new_cost + heuristic(end, next)
                        heapq.heappush(frontier, (priority, next))
                        came_from[next] = current

        return came_from, cost_so_far

        # 记录A*搜索得到的最短路径
    def reconstruct_path(came_from, start):
        end=(ROWS - 2, COLUMNS - 2)
        current = end
        path = []
        while current != start:
            path.append(current)
            current = came_from[current]
        path.append(start)
        path.reverse()
        return path
    #渲染矩形
    def draw_rect(x, y, color):
        pygame.draw.rect(screen, color, (y * roadwidth, x * roadwidth, roadwidth, roadwidth))

    #画迷宫
    def draw_maze():
        for i in range(ROWS):
            for j in range(COLUMNS):
                if matrix[i][j] == 1:
                    #draw_rect(i, j, (112, 128, 105))
                    screen.blit(image2, (j * roadwidth, i * roadwidth))
                if matrix[i][j] == 2:
                    draw_rect(i, j, "yellow")
                if matrix[i][j] == 3:
                    #draw_rect(i, j, (0,0,255))
                    screen.blit(image3, (i * roadwidth, j * roadwidth))
                if matrix[i][j] == 4:
                    draw_rect(i, j, (0, 199, 140))
                if matrix[i][j] == 5:
                    draw_rect(i, j, "white")

    matrix = matrix_init(ROWS, COLUMNS)  # 初始化迷宫
    put_node_in_to_be_selected_point([1, 1])  # 初始点旁边的备选点
    pygame.init()
    snakex = roadwidth
    snakey = roadwidth
    snakemove = roadwidth
    screen_plus=50
    screen = pygame.display.set_mode((COLUMNS * roadwidth, ROWS * roadwidth+screen_plus))
    icon = pygame.image.load('D:/Python/迷宫/780.jfif')
    pygame.display.set_icon(icon)
    pygame.display.set_caption("迷宫")
    # 生成迷宫
    for i in range(1000000):
        if len(to_be_selected_point) > 0:  # 如果还有备选点
            rand_s = random.randint(0, len(to_be_selected_point) - 1)  # 随机选点
            select_nodeA = to_be_selected_point[rand_s]  # 选择出的备选点
            select_nodeB = be_selected_near_roadpoint(select_nodeA)  # 和备选点相邻的路点
            matrix[select_nodeA[0]][select_nodeA[1]] = 0  # 把备选点成为路点
            mid_x = int((select_nodeA[0] + select_nodeB[0]) / 2)  # 备选点和路点之间的墙点
            mid_y = int((select_nodeA[1] + select_nodeB[1]) / 2)  # 同上
            matrix[mid_x][mid_y] = 0  # 把墙点成为路点
            put_node_in_to_be_selected_point(select_nodeA)  # 把以成为路点的备选点的周围的备选点加入备选列表
            to_be_selected_point.remove(select_nodeA)  # 从备选列表中移除刚刚成为路点的备选点
        else:
            break
    matrix[ROWS - 2][COLUMNS - 2] = 3  # 终点
    tip = 0
    while True:
        snakemovedirect = 0
        screen.fill("white")
        pygame.draw.polygon(screen, "gray", (
        (0, COLUMNS * roadwidth), (ROWS * roadwidth, COLUMNS * roadwidth), (ROWS * roadwidth, COLUMNS * roadwidth + screen_plus),
        (0, COLUMNS * roadwidth + screen_plus), (0, COLUMNS * roadwidth)))
        draw_maze()
        font: Font = pygame.font.SysFont('方正粗黑宋简体',30)
        time_end = time.time()
        time_c = round(time_end - time_start,1)
        text = f"用时:{time_c} s    -空格键提示-   -C键隐藏提示-"
        scorerender = font.render(text, True, (34,139,34))
        screen.blit(scorerender, (10, COLUMNS * roadwidth+screen_plus-40))
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()
            #键盘点击事件
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_RIGHT and matrix[int(snakey / roadwidth)][int(snakex / roadwidth) + 1] != 1:
                    snakemovedirect = 1
                elif event.key == pygame.K_LEFT and matrix[int(snakey / roadwidth)][int(snakex / roadwidth) - 1] != 1:
                    snakemovedirect = 2
                elif event.key == pygame.K_UP and matrix[int(snakey / roadwidth) - 1][int(snakex / roadwidth)] != 1:
                    snakemovedirect = 3
                elif event.key == pygame.K_DOWN and matrix[int(snakey / roadwidth) + 1][int(snakex / roadwidth)] != 1:
                    snakemovedirect = 4
                elif event.key == pygame.K_SPACE:
                    if tip == 0:

                    # DFS
                        # path_searching_dfs(int(snakey / roadwidth), int(snakex / roadwidth))
                    # ASTAR
                        came_from, _ = path_searching_astar((int(snakex / roadwidth),int(snakey / roadwidth)))
                        path = reconstruct_path(came_from, (int(snakex / roadwidth),int(snakey / roadwidth)))
                        for position in path:
                            matrix[position[1]][position[0]] = 2
                        matrix[ROWS - 2][COLUMNS - 2] = 3

                        tip = 1
                    for i in range(ROWS):
                        for j in range(COLUMNS):
                            if matrix[i][j] == 5:
                                matrix[i][j] = 2
                elif event.key == pygame.K_c:
                    for i in range(ROWS):
                        for j in range(COLUMNS):
                            if matrix[i][j] == 2:
                                matrix[i][j] = 5

        # for i in matrix:
        #   if i!=1:
        #      print(i)
        #玩家移动
        if snakemovedirect == 2:
            snakex -= snakemove
        if snakemovedirect == 1:
            snakex += snakemove
        if snakemovedirect == 4:
            snakey += snakemove
        if snakemovedirect == 3:
            snakey -= snakemove
        if matrix[int(snakey / roadwidth)][int(snakex / roadwidth)] == 3:
            tk1.showinfo("游戏成功", f"游戏成功,用时:{time_c}s")

        path = matrix  # 走过的路径
        path[int(snakey / roadwidth)][int(snakex / roadwidth)] = 4

        pygame.draw.rect(screen, "black", (snakex, snakey, roadwidth, roadwidth))
        screen.blit(image1, (snakex, snakey))
        pygame.display.flip()
        pygame.time.Clock().tick(10)
b=tk.Button(root,text='开始游戏',width=8,height=1,command=cul,font=('STzhongsong',20))
b.place(x=55,y=190)
def close():
    root.destroy()
bc=tk.Button(root,text='退出游戏',width=8,height=1,command=close,font=('STzhongsong',20))
bc.place(x=55,y=250)
root.mainloop()

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
课程设计-基于Python+Pygame开发的走迷宫游戏源码+使用说明+详细代码注释 【项目介绍】 该资源内项目代码都是经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载使用,也适合小白学习进阶, 或者实际项目借鉴参考! 当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。如果基础还行,也可在此代码基础上进行修改,以实现其他功能。 main.py为主函数 maze.py为随机生成迷宫函数 color.py为存储颜色函数 main_new.py为被老师验收之后自己重的主函数 mapp.py为被老师验收之后自己重的自己设计的迷宫(非随机生成迷宫) 由于时间等原因,第二种生成迷宫的AI算法还未实现 (一)课题内容 * 实现走迷宫。 * 主要功能为界面显示、上下左右键的响应以及当前步数统计。 * 通过该课题全面熟悉数组、字符串等的使用,掌握程序设计的基本方法及友好界面的设计。 (二)课题要求 ## 1. 基本要求 (1)游戏界面显示:迷宫地图、上下左右移动的特效。 (2)动作选择:上下左右键对应于上下左右的移动功能,遇到障碍的处理。 (3)得分统计功能:步数等。 ## 2. 扩展要求 (1)用户数据管理。 (2)设计一个自动走迷宫的程序,使得得到最短路径。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值