maze_python/main.py

273 lines
12 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import pygame
from pygame import Surface
from pygame.constants import QUIT
from maze import Maze
from draw import Button, Toast
from save_ui import SaveLoadUI
from config import *
import sys
import os
screen: Surface = None # 窗口实例
clock = None # 时钟实例
textFont = None # 字体
def pygameInit(title: str = "pygame"):
"""初始化 pygame"""
pygame.init()
pygame.mixer.init() # 声音初始化
pygame.display.set_caption(title)
global screen, clock, textFont # 修改全局变量
screen = pygame.display.set_mode((UI_WIDTH, UI_HEIGHT))
clock = pygame.time.Clock()
# Initialize font with UTF-8 support
pygame.font.init()
textFont = pygame.font.Font(FONT_FILE, FONT_SIZE)
def create_buttons(button_positions):
"""根据按钮位置创建所有按钮"""
# 创建按钮纹理(只需要一次)
button_start_texture = pygame.image.load(START_BUTTON_IMAGE).convert_alpha()
button_start_texture = pygame.transform.scale(button_start_texture, BUTTON_START_SIZE)
button_save_texture = pygame.image.load(SAVE_BUTTON_IMAGE).convert_alpha()
button_save_texture = pygame.transform.scale(button_save_texture, BUTTON_SAVE_SIZE)
button_load_texture = pygame.image.load(LOAD_BUTTON_IMAGE).convert_alpha()
button_load_texture = pygame.transform.scale(button_load_texture, BUTTON_SAVE_SIZE)
# 创建按钮对象
button_start = Button(pygame.rect.Rect(*button_positions['start_button'], *BUTTON_START_SIZE), button_start_texture)
button_save = Button(pygame.rect.Rect(*button_positions['save_button'], *BUTTON_SAVE_SIZE), button_save_texture)
button_load = Button(pygame.rect.Rect(*button_positions['load_button'], *BUTTON_SAVE_SIZE), button_load_texture)
button_next_step = Button(pygame.rect.Rect(*button_positions['next_step_button'], *BUTTON_CONTROL_SIZE), None)
button_reset_path = Button(pygame.rect.Rect(*button_positions['reset_path_button'], *BUTTON_CONTROL_SIZE), None)
button_auto_play = Button(pygame.rect.Rect(*button_positions['auto_play_button'], *BUTTON_CONTROL_SIZE), None)
return {
'start': button_start,
'save': button_save,
'load': button_load,
'next_step': button_next_step,
'reset_path': button_reset_path,
'auto_play': button_auto_play
}
def update_save_ui_positions(save_ui, button_positions):
"""更新存档界面的位置"""
save_ui.list_area = pygame.Rect(*button_positions['save_list_area'])
if __name__ == "__main__":
pygameInit("maze")
maze = Maze(wall_size=WALL_SIZE, maze_size=MAZE_SIZE, file_name=DEFAULT_MAZE_FILE)
# 加载图片资源(将根据需要动态缩放)
image_wall = pygame.image.load(WALL_IMAGE).convert_alpha()
image_coin = pygame.image.load(COIN_IMAGE).convert_alpha()
image_trap = pygame.image.load(TRAP_IMAGE).convert_alpha()
# 初始按钮位置和按钮
button_positions = get_button_positions()
buttons = create_buttons(button_positions)
# 提示信息
mes1 = Toast("没有生成迷宫,无法保存", UI_WIDTH, UI_HEIGHT, font=textFont)
mes2 = Toast("迷宫已保存", UI_WIDTH, UI_HEIGHT, font=textFont)
mes3 = Toast("存档已保存", UI_WIDTH, UI_HEIGHT, font=textFont)
mes4 = Toast("存档加载成功", UI_WIDTH, UI_HEIGHT, font=textFont)
mes5 = Toast("加载失败", UI_WIDTH, UI_HEIGHT, font=textFont)
# 创建存档界面
save_ui = SaveLoadUI(textFont)
update_save_ui_positions(save_ui, button_positions)
# 路径控制变量
auto_play = False
auto_play_timer = 0
auto_play_interval = AUTO_PLAY_INTERVAL
# 当前显示尺寸跟踪
current_display_size = MAZE_SIZE
running = True
while running:
clock.tick(FPS) # 限制帧数
screen.fill(COLOR_WHITE) # 铺底
# 检查迷宫显示尺寸是否发生变化,如果变化则更新按钮位置
if maze.get_actual_display_size() != current_display_size:
current_display_size = maze.get_actual_display_size()
button_positions = get_button_positions(current_display_size)
buttons = create_buttons(button_positions)
update_save_ui_positions(save_ui, button_positions)
print(f"UI布局已更新迷宫显示尺寸: {current_display_size}")
# 自动播放逻辑
if auto_play and len(maze.full_path) > 0:
auto_play_timer += 1
if auto_play_timer >= auto_play_interval:
if not maze.next_path_step():
auto_play = False # 路径播放完成后停止自动播放
auto_play_timer = 0
for event in pygame.event.get():
# 首先让存档界面处理事件
save_result = save_ui.handle_event(event, maze)
if save_result == "save_success":
mes3.show()
elif save_result == "load_success":
mes4.show()
auto_play = False # 加载游戏后停止自动播放
elif save_result == "load_failed":
mes5.show()
# 如果存档界面正在显示,不处理其他按钮事件
if not save_ui.show_save_list:
buttons['start'].handle_event(event=event)
buttons['save'].handle_event(event=event)
buttons['load'].handle_event(event=event)
buttons['next_step'].handle_event(event=event)
buttons['reset_path'].handle_event(event=event)
buttons['auto_play'].handle_event(event=event)
if buttons['start'].pressed == True:
maze.generate()
auto_play = False # 生成新迷宫时停止自动播放
if buttons['save'].pressed == True:
if len(maze.grid) == 0:
mes1.show()
else:
# 自动保存为JSON格式
result = maze.save_game(format_type="json")
if result:
mes2.text = "迷宫已保存为JSON格式"
mes2.show()
else:
mes5.text = "保存失败"
mes5.show()
if buttons['load'].pressed == True:
# 直接读取样例JSON文件并生成路径
sample_file = "saves/sample.json"
if os.path.exists(sample_file):
if maze.load_game(sample_file):
# 加载成功后重新生成路径
if maze.generater.maze:
from SourceCollector import SourceCollector
maze.source_collector = SourceCollector(maze=maze.generater.maze)
maze.source_collector.run()
maze.full_path = maze.source_collector.get_path()
maze.path_step = 0
maze.is_path_complete = False
maze.grid = maze.generater.maze # 重置显示网格
mes4.text = f"已加载 {sample_file} 并生成路径"
mes4.show()
auto_play = False
else:
mes5.text = "加载的迷宫数据无效"
mes5.show()
else:
mes5.text = f"无法加载 {sample_file}"
mes5.show()
else:
# 如果sample.json不存在则打开存档选择界面
save_ui.update_save_list(maze)
save_ui.toggle_save_list()
# 路径控制
if buttons['next_step'].pressed == True and len(maze.full_path) > 0:
maze.next_path_step()
if buttons['reset_path'].pressed == True and len(maze.full_path) > 0:
maze.reset_path()
auto_play = False
if buttons['auto_play'].pressed == True and len(maze.full_path) > 0:
auto_play = not auto_play
auto_play_timer = 0
# 键盘控制
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE and len(maze.full_path) > 0:
maze.next_path_step()
elif event.key == pygame.K_r and len(maze.full_path) > 0:
maze.reset_path()
auto_play = False
elif event.key == pygame.K_a and len(maze.full_path) > 0:
auto_play = not auto_play
auto_play_timer = 0
elif event.key == pygame.K_s and pygame.key.get_pressed()[pygame.K_LCTRL]:
# Ctrl+S 保存包含路径的JSON
if len(maze.grid) > 0:
result = maze.save_game(format_type="json")
if result:
mes3.text = "JSON格式存档已保存"
mes3.show()
elif event.key == pygame.K_s and pygame.key.get_pressed()[pygame.K_LSHIFT]:
# Shift+S 保存为CSV格式兼容旧版本
if len(maze.grid) > 0:
result = maze.save_game(format_type="csv")
if result:
mes3.text = "CSV格式存档已保存"
mes3.show()
elif event.key == pygame.K_l and pygame.key.get_pressed()[pygame.K_LCTRL]:
# Ctrl+L 打开读档界面
save_ui.update_save_list(maze)
save_ui.toggle_save_list()
if event.type == QUIT:
running = False
maze.draw(screen=screen, wall_texture=image_wall, coin_texture=image_coin, trap_texture=image_trap)
buttons['start'].draw(screen=screen)
buttons['save'].draw(screen=screen)
buttons['load'].draw(screen=screen)
# 绘制路径控制按钮
if len(maze.full_path) > 0:
# 绘制按钮背景
pygame.draw.rect(screen, COLOR_GRAY, buttons['next_step'].rect)
pygame.draw.rect(screen, COLOR_GRAY, buttons['reset_path'].rect)
pygame.draw.rect(screen, COLOR_GREEN if auto_play else COLOR_GRAY, buttons['auto_play'].rect)
# 绘制按钮文字
next_text = textFont.render("下一步", True, COLOR_BLACK)
reset_text = textFont.render("重置", True, COLOR_BLACK)
auto_text = textFont.render("自动播放" if not auto_play else "停止", True, COLOR_BLACK)
screen.blit(next_text, (buttons['next_step'].rect.x + 10, buttons['next_step'].rect.y + 15))
screen.blit(reset_text, (buttons['reset_path'].rect.x + 25, buttons['reset_path'].rect.y + 15))
screen.blit(auto_text, (buttons['auto_play'].rect.x + 5, buttons['auto_play'].rect.y + 15))
# 显示当前步数信息
progress_text = textFont.render(f"路径进度: {maze.path_step}/{len(maze.full_path)}", True, COLOR_BLACK)
screen.blit(progress_text, button_positions['progress_text'])
# 显示操作提示
if len(maze.full_path) > 0:
hint_text = textFont.render("空格键: 下一步 | R键: 重置 | A键: 自动播放", True, COLOR_LIGHT_GRAY)
screen.blit(hint_text, button_positions['hint_text'])
# 显示快捷键提示
shortcut_text = textFont.render("Ctrl+S: 保存JSON | Shift+S: 保存CSV | Ctrl+L: 读档", True, COLOR_LIGHT_GRAY)
screen.blit(shortcut_text, button_positions['shortcut_text'])
mes1.draw(screen=screen)
mes2.draw(screen=screen)
mes3.draw(screen=screen)
mes4.draw(screen=screen)
mes5.draw(screen=screen)
# 绘制存档界面(必须在最后绘制以显示在最上层)
save_ui.draw(screen)
pygame.display.flip()
pygame.quit()