from modules.Sprites import *
from modules.mazes import *
from modules.pathfinding import *
'''主函数'''
def main(cfg):
# ----初始化
pygame.init()
pygame.font.init()
screen = pygame.display.set_mode(cfg.SCREENSIZE)
pygame.display.set_caption('Maze')
# ----字体
font = pygame.font.SysFont(cfg.FONT, 15)
font_button = pygame.font.SysFont(cfg.FONT, 15) # 按钮字体
font_button.set_underline(True) # 按钮字体开启下划线
font_focus = pygame.font.SysFont(cfg.FONT, 25) # 按钮焦点字体
# ----三个界面
modes = {'start': 'game_start', 'switch': 'game_switch', 'end': 'game_end'}
# ----开始界面
choice = Interface(screen, cfg, modes['start'])
# start or restart
while True:
# ---退出游戏
if not choice:
pygame.quit()
sys.exit(-1)
# ---设置界面 返回迷宫生成算法
arithmetic = setting(screen, cfg)
# ---记录关卡数
num_levels = 0
# ---关卡循环切换
while True:
num_levels += 1
clock = pygame.time.Clock()
screen = pygame.display.set_mode(cfg.SCREENSIZE)
# --随机生成关卡地图
maze_now = RandomMaze(cfg.MAZESIZE, cfg.BLOCKSIZE, cfg.BORDERSIZE, arithmetic, cfg.STARTPOINT,
cfg.DESTINATION)
# --生成hero
start = [cfg.STARTPOINT[1], cfg.STARTPOINT[0]]
hero_now = Hero(cfg.HEROPICPATH, start, cfg.BLOCKSIZE, cfg.BORDERSIZE)
# --统计步数
num_steps = 0
# --记录路径
move_records = []
# --寻路功能按钮:显示路径 直接通关
path_finding = ["Do you want to cheat?","Cheat(A*)","Do you want to continue"]
path_n = 0
# --预先获取位置
rect = pygame.Rect(10, 10, font.size('Level Done: %d' % num_levels)[0],
font.size('Level Done: %d' % num_levels)[1])
button = Label_ce(screen, font_button, path_finding[path_n], cfg.HIGHLIGHT,
(cfg.SCREENSIZE[0] - font_button.size(path_finding[0])[0], rect.centery))
# --关卡内主循环
while True:
dt = clock.tick(cfg.FPS)
screen.fill((255, 255, 255))
is_move = False
# ----寻找路径
if path_n ==0:
guide, searched = A_Star(maze_now, hero_now.coordinate, cfg.DESTINATION)
# ----显示移动路径
for move in move_records:
pygame.draw.circle(screen, cfg.HIGHLIGHT, move, 2)
# ----显示路径
if path_n != 0:
for move in searched:
pygame.draw.circle(screen, cfg.LINE, move, 2)
for move in guide:
pygame.draw.circle(screen, cfg.FOREGROUND, move, 2)
# ----显示一些信息
Label_co(screen, font, 'Level Done: %d' % num_levels, cfg.HIGHLIGHT, (10, 10))
Label_co(screen, font, 'Used Steps: %s' % num_steps, cfg.HIGHLIGHT, (cfg.SCREENSIZE[0] // 4 + 10, 10))
Label_co(screen, font, 'Min Cost: %s' % (len(guide) - 1), cfg.HIGHLIGHT,
(cfg.SCREENSIZE[0] // 2 + 10, 10))
Label_co(screen, font, 'S: your starting point D: your destination', cfg.HIGHLIGHT,
(10, cfg.SCREENSIZE[1] - font.size('')[1] - 10))
# ----显示按钮
if button.collidepoint(pygame.mouse.get_pos()):
button = Label_ce(screen, font_focus, path_finding[path_n], cfg.HIGHLIGHT,
(cfg.SCREENSIZE[0] - font_button.size(path_finding[0])[0], rect.centery))
else:
button = Label_ce(screen, font_button, path_finding[path_n], cfg.HIGHLIGHT,
(cfg.SCREENSIZE[0] - font_button.size(path_finding[0])[0], rect.centery))
# ----事件响应 ↑↓←→控制hero
for event in pygame.event.get():
# 退出
if event.type == pygame.QUIT:
pygame.quit()
sys.exit(-1)
# 点击事件
elif event.type == pygame.MOUSEBUTTONDOWN:
if path_n != 2:
path_n += 1
else:
move_records += guide
hero_now.coordinate[0] = cfg.DESTINATION[1]
hero_now.coordinate[1] = cfg.DESTINATION[0]
# 键盘事件
elif event.type == pygame.KEYDOWN:
# 判断是否移动
if event.key == pygame.K_UP:
is_move = hero_now.move('Up', maze_now)
elif event.key == pygame.K_DOWN:
is_move = hero_now.move('Down', maze_now)
elif event.key == pygame.K_LEFT:
is_move = hero_now.move('Left', maze_now)
elif event.key == pygame.K_RIGHT:
is_move = hero_now.move('Right', maze_now)
num_steps += int(is_move)
# 添加移动记录
if is_move:
left, top = hero_now.coordinate[0] * cfg.BLOCKSIZE + cfg.BORDERSIZE[0], hero_now.coordinate[
1] * cfg.BLOCKSIZE + cfg.BORDERSIZE[1]
move_records.append((left + cfg.BLOCKSIZE // 2, top + cfg.BLOCKSIZE // 2))
hero_now.draw(screen)
maze_now.draw(screen)
# ----判断游戏是否胜利
if (hero_now.coordinate[0] == cfg.DESTINATION[1]) and (hero_now.coordinate[1] == cfg.DESTINATION[0]):
break
pygame.display.update()
# --关卡切换
choice = Interface(screen, cfg, modes['switch'])
if not choice:
break
choice = Interface(screen, cfg, modes['end'])
if __name__ == '__main__':
# 读入配置
read_cfg(cfg)
main(cfg)
'''配置文件'''
import json
SCREENSIZE = (800, 625)
HEROPICPATH = 'resources/images/hero.png'
# font
FONT = 'SegoeScript'
FONT2 = 'Consolas'
# colors
BACKGROUND = (255, 255, 255)
FOREGROUND = (0, 0, 0)
HIGHLIGHT = (255, 0, 0)
LINE = (185, 185, 185)
FPS = 30
# 迷宫相关
BLOCKSIZE = 15
MAZESIZE = [15, 10] # num_rows * num_cols
STARTPOINT = [1, 1]
DESTINATION = [15, 10]
BORDERSIZE = ((SCREENSIZE[0] - MAZESIZE[1] * BLOCKSIZE) // 2, (SCREENSIZE[1] - MAZESIZE[0] * BLOCKSIZE) // 2)
'''写入配置'''
def write_cfg():
cfgs = {'MAZESIZE': MAZESIZE, 'STARTPOINT': STARTPOINT, 'DESTINATION': DESTINATION}
fp = open('cfg.txt', 'w')
json.dump(cfgs, fp)
fp.close()
'''读出配置'''
def read_cfg():
fp = open('cfg.txt', 'r')
cfgs = json.load(fp)
fp.close()
return cfgs
import random
import cfg
from modules.misc import *
'''一个游戏地图块'''
class Block(object):
def __init__(self, coordinate, block_size, border_size):
# (col, row)
self.coordinate = coordinate
self.block_size = block_size
self.border_size = border_size
self.is_visited = False
# 上下左右有没有墙
self.has_walls = [True, True, True, True]
self.color = (0, 0, 0)
'''画到屏幕上'''
def draw(self, screen):
directions = ['top', 'bottom', 'left', 'right']
for idx, direction in enumerate(directions):
if self.has_walls[idx]:
if direction == 'top':
x1 = self.coordinate[0] * self.block_size + self.border_size[0]
y1 = self.coordinate[1] * self.block_size + self.border_size[1]
x2 = (self.coordinate[0] + 1) * self.block_size + self.border_size[0]
y2 = self.coordinate[1] * self.block_size + self.border_size[1]
pygame.draw.line(screen, self.color, (x1, y1), (x2, y2))
elif direction == 'bottom':
x1 = self.coordinate[0] * self.block_size + self.border_size[0]
y1 = (self.coordinate[1] + 1) * self.block_size + self.border_size[1]
x2 = (self.coordinate[0] + 1) * self.block_size + self.border_size[0]
y2 = (self.coordinate[1] + 1) * self.block_size + self.border_size[1]
pygame.draw.line(screen, self.color, (x1, y1), (x2, y2))
elif direction == 'left':
x1 = self.coordinate[0] * self.block_size + self.border_size[0]
y1 = self.coordinate[1] * self.block_size + self.border_size[1]
x2 = self.coordinate[0] * self.block_size + self.border_size[0]
y2 = (self.coordinate[1] + 1) * self.block_size + self.border_size[1]
pygame.draw.line(screen, self.color, (x1, y1), (x2, y2))
elif direction == 'right':
x1 = (self.coordinate[0] + 1) * self.block_size + self.border_size[0]
y1 = self.coordinate[1] * self.block_size + self.border_size[1]
x2 = (self.coordinate[0] + 1) * self.block_size + self.border_size[0]
y2 = (self.coordinate[1] + 1) * self.block_size + self.border_size[1]
pygame.draw.line(screen, self.color, (x1, y1), (x2, y2))
return True
'''随机生成迷宫类'''
class RandomMaze(object):
# maze_size:迷宫大小;block_size:格子大小;border_size:边框大小
def __init__(self, maze_size, block_size, border_size, arithmetic, starting_point, destination, ):
self.block_size = block_size
self.border_size = border_size
self.maze_size = maze_size
self.starting_point = starting_point
self.destination = destination
if arithmetic == 'Prim':
self.blocks_list = RandomMaze.createMaze_Prim(maze_size, block_size, border_size)
self.font = pygame.font.SysFont(cfg.FONT, 12)
'''画到屏幕上'''
def draw(self, screen):
for row in range(self.maze_size[0]):
for col in range(self.maze_size[1]):
self.blocks_list[row][col].draw(screen)
# 起点和终点标志
Label_ce(screen, self.font, 'S', (255, 0, 0),
(self.starting_point[1] * self.block_size + self.border_size[0] + 8, self.starting_point[
0] * self.block_size + self.border_size[1] + 8))
Label_ce(screen, self.font, 'D', (255, 0, 0),
(self.destination[1] * self.block_size + self.border_size[0] + 8, self.destination[
0] * self.block_size + self.border_size[1] + 8))
@staticmethod
def createMaze_Prim(maze_size, block_size, border_size):
# ----生成全是墙的迷宫
blocks_list = [[Block([col, row], block_size, border_size) for col in range(maze_size[1])] for row in
range(maze_size[0])]
# ----将一个单元格加入列表
block_now = blocks_list[0][0]
records = [block_now]
# ----当列表不空时
while records:
# ---随机取出一个单元格
block_now = random.choice(records)
# ---标记访问 加入迷宫
block_now.is_visited = True
# ---从列表中移除这个单元格
records.remove(block_now)
# ---检查相邻单元格 上下左右
check = []
c, r = block_now.coordinate[0], block_now.coordinate[1]
check_list = [
{'check': r > 0, 'coordinate': (r - 1, c), 'direction': 'Up', 'index': 1},
{'check': r < maze_size[0] - 1, 'coordinate': (r + 1, c), 'direction': 'Down', 'index': 0},
{'check': c > 0, 'coordinate': (r, c - 1), 'direction': 'Left', 'index': 3},
{'check': c < maze_size[1] - 1, 'coordinate': (r, c + 1), 'direction': 'Right', 'index': 2}
]
for item in check_list:
# 如果单元格合法
if item['check']:
# 如果该相邻单元格在已在迷宫中,记录该单元格
if blocks_list[item['coordinate'][0]][item['coordinate'][1]].is_visited:
check.append(item['direction'])
else:
# 否则 若该单元格不在列表中,加入列表
if not blocks_list[item['coordinate'][0]][item['coordinate'][1]] in records:
records.append(blocks_list[item['coordinate'][0]][item['coordinate'][1]])
if check:
# 从记录的相邻单元格中随机选择一个单元格,将中间的墙拆除
move_direction = random.choice(check)
for index, item in enumerate(check_list):
if item['direction'] == move_direction:
blocks_list[r][c].has_walls[index] = False
blocks_list[item['coordinate'][0]][item['coordinate'][1]].has_walls[item['index']] = False
break
return blocks_list
import re
import sys
import pygame
from pygame.locals import *
import pygame.font
import pygame.event
import pygame.draw
def read_cfg(cfg):
cfgs = cfg.read_cfg()
cfg.MAZESIZE = cfgs['MAZESIZE']
cfg.STARTPOINT = cfgs['STARTPOINT']
cfg.DESTINATION = cfgs['DESTINATION']
'''Label: 在指定位置(中心)显示文字'''
def Label_ce(screen, font, text, color, position):
text_render = font.render(text, True, color) # 文本样式
rect = text_render.get_rect() # 文本位置
rect.centerx, rect.centery = position
return screen.blit(text_render, rect)
'''Label: 在指定位置(左上角)显示文字'''
def Label_co(screen, font, text, color, position):
text_render = font.render(text, True, color) # 文本样式
rect = text_render.get_rect() # 文本位置
rect.left, rect.top = position
return screen.blit(text_render, rect)
'''setting: 检查输入设置文本格式是否正确'''
def check_setted(cfg):
setted = [True, False, False, False, False]
# ----类型转换为字符串
for key in cfg.keys():
cfg[key] = str(cfg[key])
# ----Rows是否为数字
if cfg['Rows'].isdigit():
# ----转换为数字
cfg['Rows'] = int(cfg['Rows'])
# ----检查数字范围(0,35]
if 0 < cfg['Rows'] <= 35:
setted[1] = True
# ----Cols是否为数字
if cfg['Cols'].isdigit():
# ----转换为数字
cfg['Cols'] = int(cfg['Cols'])
# ----检查数字范围(0,50]
if 0 < cfg['Cols'] <= 50:
setted[2] = True
# ----正则表达式 匹配起点,终点输入格式
pattern = re.compile('^\[(\d{1,})[,*,*\s]*(\d{1,})\]$')
g = pattern.match(cfg['Starting point'])
if g:
x, y = g.group(1), g.group(2)
cfg['Starting point'] = [int(x), int(y)]
if setted[1] and setted[2] and 0 < cfg['Starting point'][0] <= cfg['Rows'] and 0 < cfg['Starting point'][1] <= \
cfg['Cols']:
setted[3] = True
g = pattern.match(cfg['Destination'])
if g:
x, y = g.group(1), g.group(2)
cfg['Destination'] = [int(x), int(y)]
if setted[1] and setted[2] and 0 < cfg['Destination'][0] <= cfg['Rows'] and 0 < cfg['Destination'][1] <= cfg[
'Cols']:
setted[4] = True
return setted
'''setting: 输入框显示'''
# 字体,是否为焦点输入框,输入问题,输入回答,输入提示,字体颜色,输入框位置,输入框最大宽度
def InputBox(screen, font, focus, question, ans, hint, color, position, max):
# ----焦点输入框设置字体斜体
font.set_italic(focus)
# ----根据本身宽度、最大宽度求空格数
width, height = font.size(question + ans + hint)
blank = (max - position[0] - width) // 2 // font.size(' ')[0]
left = (max - position[0] - width - blank * font.size(' ')[0]) // font.size(' ')[0]
# ----输入问题显示
rect = Label_co(screen, font, question, color, position)
# ----输入回答显示
x, y = rect.left + rect.width, rect.top # 根据输入问题位置求显示位置
font.set_underline(focus) # 焦点输入框输入回答位置设置下划线
rect2 = Label_co(screen, font, ' ' * blank + ans + ' ' * left, color, (x, y))
font.set_underline(False)
# ----输入提示显示
Label_co(screen, font, hint, color, (rect2.left + rect2.width, y))
font.set_italic(False)
return pygame.Rect(rect.left, rect.top, max - position[0], rect.height)
'''setting: 界面设置及其响应事件(包含按钮、输入框)'''
def setting(screen, cfg):
read_cfg(cfg)
# ----字体样式
font_title = pygame.font.SysFont(cfg.FONT, 80) # 标题字体
font = pygame.font.SysFont(cfg.FONT2, 45) # 输入框字体
font_warn = pygame.font.SysFont(cfg.FONT2, 20) # 提示字体
font_start = pygame.font.SysFont(cfg.FONT, 70) # 按钮字体
font_start.set_underline(True) # 按钮字体开启下划线
font_start_focus = pygame.font.SysFont(cfg.FONT, 85) # 按钮焦点字体
# ----设置
cfg_now = {'Rows': cfg.MAZESIZE[0], 'Cols': cfg.MAZESIZE[1], 'Starting point': cfg.STARTPOINT,
'Destination': cfg.DESTINATION}
# ----设置检查
setted = check_setted(cfg_now)
# ----设置正误相关提示
warnings = {'Correct': 'Correct settings', 'Incorrect': 'Incorrect settings'}
# ----输入框相关参数:行数、列数、起点、终点
focus = ['title', 'Rows', 'Cols', 'Starting point', 'Destination'] # 标题 输入问题
hint = {'Rows': '(0<rows<=35)', 'Cols': '(0 < cols <= 50)', 'Starting point': ' ', 'Destination': ' '} # 输入提示
color = {'True': cfg.HIGHLIGHT, 'False': cfg.FOREGROUND}
# ----焦点输入框下标 默认第一个
focus_now = 1
# ----按钮:Randomized Prim's algorithm、Recursive backtracking
buttons = {'Prim': Label_ce(screen, font_start, 'Prim', cfg.FOREGROUND,
(cfg.SCREENSIZE[0] // 4, cfg.SCREENSIZE[1] - font_start.size('')[1] // 2)),
}
# ----setting主循环
while True:
screen.fill(cfg.BACKGROUND)
# ----绘制标题
labels = {'title': Label_co(screen, font_title, 'Setting:', cfg.FOREGROUND, (10, 0)),
'Rows': None, 'Cols': None, 'Starting point': None, 'Destination': None}
pygame.draw.line(screen, cfg.LINE, (0, labels['title'].top + labels['title'].height - 20),
# (labels['title'].left + labels['title'].width + 400,
(cfg.SCREENSIZE[0], labels['title'].top + labels['title'].height - 20)) # 分割线
# ----绘制输入框(区分焦点输入框)
for i in range(1, 5):
labels[focus[i]] = InputBox(screen, font, i == focus_now, focus[i] + ': ', str(cfg_now[focus[i]]),
hint[focus[i]], color[str(i == focus_now)],
(20, labels[focus[i - 1]].top + labels[focus[i - 1]].height + 30),
cfg.SCREENSIZE[0])
# ----显示提醒
if setted.count(True) == 5: # 设置正确
warn = warnings['Correct']
else:
warn = warnings['Incorrect']
warning = Label_co(screen, font_warn, '· Tips: ' + warn, cfg.HIGHLIGHT,
(20, cfg.SCREENSIZE[1] - font_start_focus.size('')[1] - 30))
pygame.draw.line(screen, cfg.LINE, (0, warning.top + warning.height),
(cfg.SCREENSIZE[0], warning.top + warning.height)) # 分割线
# ----按钮 区分设置正确与否 区分焦点
for key in buttons.keys():
if buttons[key].collidepoint(pygame.mouse.get_pos()) and warn == warnings['Correct']:
buttons[key] = Label_ce(screen, font_start_focus, key, cfg.FOREGROUND,
(buttons[key].centerx, buttons[key].centery));
else:
buttons[key] = Label_ce(screen, font_start, key, cfg.FOREGROUND,
(buttons[key].centerx, buttons[key].centery));
# ----当前焦点输入框的内容
current_string = list(str(cfg_now[focus[focus_now]]))
# ----事件响应
for event in pygame.event.get():
# 退出游戏
if event.type == pygame.QUIT:
pygame.quit()
sys.exit(-1)
# 鼠标点击
elif event.type == pygame.MOUSEBUTTONDOWN:
# 点击按钮 检查按钮及是否可按(设置是否正确)
for key in buttons.keys():
if buttons[key].collidepoint(pygame.mouse.get_pos()) and warn == warnings['Correct']:
# 正确->修改配置
cfg.MAZESIZE = [cfg_now['Rows'], cfg_now['Cols']]
cfg.STARTPOINT = cfg_now['Starting point']
cfg.DESTINATION = cfg_now['Destination']
cfg.BORDERSIZE = (
(cfg.SCREENSIZE[0] - cfg.MAZESIZE[1] * cfg.BLOCKSIZE) // 2,
(cfg.SCREENSIZE[1] - cfg.MAZESIZE[0] * cfg.BLOCKSIZE) // 2)
cfg.write_cfg() # 将新配置写入配置文件
cfg.STARTPOINT = [cfg_now['Starting point'][0] - 1, cfg_now['Starting point'][1] - 1]
cfg.DESTINATION = [cfg_now['Destination'][0] - 1, cfg_now['Destination'][1] - 1]
return key
# 点击标签
for key in labels.keys():
if labels[key].collidepoint(pygame.mouse.get_pos()) and key != 'title':
focus_now = focus.index(key)
# 键盘输入
elif event.type == KEYDOWN:
inkey = event.key
if inkey == K_BACKSPACE: # 撤销
current_string = current_string[0:-1]
cfg_now[focus[focus_now]] = ''.join(current_string) # 更新字符串
elif inkey == K_RETURN or inkey == K_RIGHT or inkey == K_DOWN: # 下个输入框
if focus_now < 4:
focus_now = focus_now + 1
elif inkey == K_LEFT or inkey == K_UP: # 上个输入框
if focus_now > 1:
focus_now = focus_now - 1
elif inkey <= 127: # 输入字符
current_string.append(chr(inkey))
cfg_now[focus[focus_now]] = ''.join(current_string) # 更新字符串
else:
pass
# 设置更新
setted = check_setted(cfg_now)
# 界面更新
pygame.display.update()
'''Interface: 其他界面设置及其响应事件(包含按钮)'''
def Interface(screen, cfg, mode='game_start', title='Maze'):
# ----字体样式
font_title = pygame.font.SysFont(cfg.FONT, 120) # 标题字体
font = pygame.font.SysFont(cfg.FONT, 55) # 按钮字体
font.set_underline(True) # 按钮字体开启下划线
font_focus = pygame.font.SysFont(cfg.FONT, 100) # 焦点按钮字体
# ----按钮样式
label_title = {'font': font_title, 'font_focus': font_title, 'text': title, 'color': cfg.HIGHLIGHT,
'position': ((cfg.SCREENSIZE[0]) // 2, cfg.SCREENSIZE[1] // 4)}
label_continue = {'font': font, 'font_focus': font_focus, 'text': 'Start', 'color': cfg.FOREGROUND,
'position': ((cfg.SCREENSIZE[0]) // 2, cfg.SCREENSIZE[1] // 2)}
label_quit = {'font': font, 'font_focus': font_focus, 'text': 'Quit', 'color': cfg.FOREGROUND,
'position': ((cfg.SCREENSIZE[0]) // 2, cfg.SCREENSIZE[1] - cfg.SCREENSIZE[1] // 3)}
label_format = {'title': label_title, 'continue': label_continue, 'quit': label_quit}
if mode == 'game_switch':
label_continue['text'] = 'Next'
elif mode == 'game_end':
label_continue['text'] = 'Restart'
# ----按钮
buttons = {'title': None, 'continue': None, 'quit': None}
clock = pygame.time.Clock()
screen.fill(cfg.BACKGROUND)
for key in buttons.keys():
buttons[key] = Label_ce(screen, label_format[key]['font'], label_format[key]['text'],
label_format[key]['color'],
label_format[key]['position'])
pygame.draw.line(screen, cfg.LINE,
(buttons['title'].left - 100, buttons['title'].top + buttons['title'].height - 40), (
buttons['title'].left + buttons['title'].width + 100,
buttons['title'].top + buttons['title'].height - 40))
# ----Logo图片
image = pygame.image.load(cfg.HEROPICPATH)
image = pygame.transform.scale(image, (50, 50))
rect = image.get_rect()
rect.centerx, rect.centery = buttons['title'].centerx + buttons['title'].width // 2 + 25, buttons[
'title'].centery + 30
screen.blit(image, rect)
# ----界面主循环
while True:
screen.fill(cfg.BACKGROUND)
# 绘制按钮 区分焦点
for key in buttons.keys():
if buttons[key].collidepoint(pygame.mouse.get_pos()):
buttons[key] = Label_ce(screen, label_format[key]['font_focus'], label_format[key]['text'],
label_format[key]['color'], label_format[key]['position'])
else:
buttons[key] = Label_ce(screen, label_format[key]['font'], label_format[key]['text'],
label_format[key]['color'], label_format[key]['position'])
pygame.draw.line(screen, cfg.LINE,
(buttons['title'].left - 100, buttons['title'].top + buttons['title'].height - 40), (
buttons['title'].left + buttons['title'].width + 100,
buttons['title'].top + buttons['title'].height - 40))
# 绘制Logo
screen.blit(image, rect)
# 事件响应
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit(-1)
elif event.type == pygame.MOUSEBUTTONDOWN:
if buttons['continue'].collidepoint(pygame.mouse.get_pos()):
return True
elif buttons['quit'].collidepoint(pygame.mouse.get_pos()):
return False
pygame.display.update()
clock.tick(cfg.FPS)
'''迷宫坐标求显示位置'''
def get_pos(coordinate, block_size, border_size):
l, t = coordinate[1] * block_size + border_size[0], coordinate[0] * block_size + border_size[1]
coordinate = (l + block_size // 2, t + block_size // 2)
return coordinate
'''查表 有返回下标 无返回-1'''
def check(r, c, table):
for index, item in enumerate(table):
if item['r'] == r and item['c'] == c:
return index
return -1
'''A* search'''
def A_Star(maze, starting_point, destination):
# ----计算曼哈顿距离
def weight(r, c, dis, er=destination[0], ec=destination[1]):
return dis + abs(r - er) + abs(c - ec)
# ----获取查询过的地图块
def get_searched(block_size, border_size, table):
searched = []
for item in table:
searched.append(get_pos((item['r'], item['c']), block_size, border_size))
return searched
path = [] # 最终路径
open = [] # open表 能走的路
close = [] # close表 已经走了的路
# UP DOWN LEFT RIGHT
directions = [(0, -1), (0, 1), (-1, 0), (1, 0)]
block = {'parent': -1, 'r': starting_point[1], 'c': starting_point[0], 'dis': 0,
'f': weight(starting_point[1], starting_point[0], 0)}
# 添加起点
open.append(block)
while open:
# --open根据f值表排序 取优先级最高的结点
open = sorted(open, key=lambda x: x['f'], reverse=True)
block = open.pop()
# --加入close表
close.append(block)
# 已到达终点 根据close返回路径
if block['r'] == destination[0] and block['c'] == destination[1]:
next = len(close) - 1
while next != -1:
coordinate = (close[next]['r'], close[next]['c'])
path.append(get_pos(coordinate, maze.block_size, maze.border_size))
next = close[next]['parent']
return path, get_searched(maze.block_size, maze.border_size, open + close)
# 遍历当前结点邻近结点
for i in range(0, 4):
block_new = {'parent': check(block['r'], block['c'], close), 'r': block['r'] + directions[i][1],
'c': block['c'] + directions[i][0], 'dis': block['dis'] + 1,
'f': weight(block['r'] + directions[i][1], block['c'] + directions[i][0], block['dis'] + 1)}
# 检查是否在close表中
p = check(block_new['r'], block_new['c'], close)
# 没有墙且不在close中
if not maze.blocks_list[block['r']][block['c']].has_walls[i] and p == -1:
# 检查是否在open表中
idx = check(block_new['r'], block_new['c'], open)
# 不在 添进open表中
if idx == -1:
open.append(block_new)
# 在 比较路径距离 短则更新
else:
if open[idx]['dis'] > block_new['dis']:
open[idx] = block_new
# open表为空 路径不存在
return path, get_searched(maze.block_size, maze.border_size, open + close)
import pygame
'''定义hero'''
class Hero(pygame.sprite.Sprite):
def __init__(self, imagepath, coordinate, block_size, border_size, **kwargs):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(imagepath)
self.image = pygame.transform.scale(self.image, (block_size, block_size))
self.rect = self.image.get_rect()
self.rect.left, self.rect.top = coordinate[0] * block_size + border_size[0], coordinate[1] * block_size + \
border_size[1]
self.coordinate = coordinate
self.block_size = block_size
self.border_size = border_size
'''移动'''
def move(self, direction, maze):
blocks_list = maze.blocks_list
# 上下左右对应坐标的加减
directions = {'Up': (0, -1), 'Down': (0, 1), 'Left': (-1, 0), 'Right': (1, 0)}
for index, key in enumerate(directions.keys()):
if direction == key:
if blocks_list[self.coordinate[1]][self.coordinate[0]].has_walls[index]:
return False
else:
self.coordinate[0] += directions[key][0]
self.coordinate[1] += directions[key][1]
return True
'''绑定到屏幕'''
def draw(self, screen):
self.rect.left, self.rect.top = self.coordinate[0] * self.block_size + self.border_size[0], self.coordinate[
1] * self.block_size + self.border_size[1]
screen.blit(self.image, self.rect)