20241123实验四 《Python程序设计》实验报告
20241123 2024-2025-2 《Python程序设计》实验四报告
课程:《Python程序设计》
班级: 2411
姓名: 胡钧涛
学号:20241123
实验教师:王志强
实验日期:2025年5月14日
必修/选修: 公选课
实验前言(设计原因)
小的时候也许大家都玩过诸如俄罗斯方块、贪吃蛇、推箱子之类的小游戏,而现在我学习了python之后,第一个想法就是以这些小游戏为灵感,在这基础上再加上一些自己的设计,所以这次的实验四我就以推箱子这款小游戏为模板,开始了自己的编码旅程(狗头)
实验内容
先简略编写出基层代码,实现对这款游戏的初步设计,其次,引入自己喜欢的人物图片作为游戏主人公,并在里面加入自己想要的游戏特效
实验过程(相应代码内容和设计步骤)
一安装所需要的平台
使用python写游戏,有一个必定绕不开的环节,那就是pygame安装,它是一个专门用于开发 2D 游戏和多媒体应用的 Python 库,提供了一系列丰富的功能模块,让开发者可以轻松实现图形渲染、音频处理、用户输入等游戏开发所需的核心功能,所以我们首先要下载安装pygame

推箱子游戏代码
对函数的引入和初始化
import pygame
import sys
import json
import os
from typing import Dict, Tuple, List, Optional, Any
import random
# 初始化 Pygame
pygame.init()
对游戏底层功能的实现
# 确保中文正常显示
pygame.font.init()
font = pygame.font.SysFont(['SimHei', 'WenQuanYi Micro Hei', 'Heiti TC'], 36)
small_font = pygame.font.SysFont(['SimHei', 'WenQuanYi Micro Hei', 'Heiti TC'], 24)
tiny_font = pygame.font.SysFont(['SimHei', 'WenQuanYi Micro Hei', 'Heiti TC'], 16)
# 游戏常量
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
TILE_SIZE = 50 # 游戏格子大小
PLAYER_SIZE = 50 # 人物图片尺寸
FPS = 60
# 颜色定义
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
WALL_COLOR = (50, 50, 200)
BOX_COLOR = (200, 100, 50)
TARGET_COLOR = (50, 200, 50)
PLAYER_COLOR = (200, 50, 50)
BOX_ON_TARGET_COLOR = (150, 150, 0)
BACKGROUND_COLOR = (230, 230, 230)
MENU_COLOR = (200, 200, 200)
BUTTON_COLOR = (100, 150, 200)
BUTTON_HOVER_COLOR = (120, 170, 220)
ERROR_COLOR = (255, 100, 100)
# 方向定义
UP = (0, -1)
DOWN = (0, 1)
LEFT = (-1, 0)
RIGHT = (1, 0)
# 创建游戏窗口
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("推箱子")
clock = pygame.time.Clock()
此外,为了使我设计的游戏更具趣味性,我又添加了通关撒花代码的设计(这里可以根据个人需要,可有可无)
# 撒花效果颜色
CONFETTI_COLORS = [
(255, 0, 0), # 红色
(255, 165, 0), # 橙色
(255, 255, 0), # 黄色
(0, 128, 0), # 绿色
(0, 0, 255), # 蓝色
(75, 0, 130), # 靛色
(238, 130, 238) # 紫色
]
撒花效果类
class Confetti:
def __init__(self, count: int = 100) -> None:
self.particles = []
self.count = count
self.reset()
def reset(self) -> None:
"""重置所有粒子"""
self.particles = []
for _ in range(self.count):
self.particles.append(self.create_particle())
def create_particle(self) -> Dict[str, Any]:
"""创建单个粒子"""
return {
'x': random.randint(0, SCREEN_WIDTH),
'y': random.randint(-50, 0),
'size': random.randint(2, 6),
'color': random.choice(CONFETTI_COLORS),
'speed_x': random.uniform(-2, 2),
'speed_y': random.uniform(2, 5),
'rotation': random.uniform(0, 360),
'rotation_speed': random.uniform(-5, 5)
}
def update(self) -> None:
"""更新所有粒子状态"""
for particle in self.particles:
particle['x'] += particle['speed_x']
particle['y'] += particle['speed_y']
particle['rotation'] += particle['rotation_speed']
# 如果粒子飞出屏幕底部,重新放置到顶部
if particle['y'] > SCREEN_HEIGHT:
particle['y'] = random.randint(-50, 0)
particle['x'] = random.randint(0, SCREEN_WIDTH)
def draw(self, screen: pygame.Surface) -> None:
"""绘制所有粒子"""
for particle in self.particles:
rect = pygame.Rect(particle['x'], particle['y'], particle['size'], particle['size'])
pygame.draw.rect(screen, particle['color'], rect)
在设计游戏关卡时,我暂时没找到怎么让游戏本身自己生成,或者是太复杂了,我现在还学不会,所以我就自己手动设置关卡了,这个笨办法虽然好用就是有点费手
# 游戏关卡
levels = [
# 关卡 1
[
"############",
"# #",
"# ##### #",
"# # # #",
"# # @### ##",
"# # $ $ $ #",
"# # .# #",
"# # ...# #",
"# # ...# #",
"# # .# #",
"# #",
"############"
],
# 关卡 2
[
"############",
"# ##### #",
"# # # #",
"# #$ # #",
"# ### # ## #",
"# # # ##",
"# # # @# #",
"# # #$ $# #",
"# #.##.# ##",
"# #...# #",
"# ##### #",
"############"
],
# 关卡 3
[
"############",
"# # #",
"# # #####",
"# $ $ $ #",
"# # #$ #",
"# # ## #",
"# @# $ # #",
"## # # ##",
" # # # #",
" # ..# # #",
" # ...# #",
"############"
]
]
另外,由于python本身生成游戏人物和箱子的素材太丑,所以我就自己在网上找了几组图片,引入素材使用的代码,自己设计了这款游戏的元素
class AssetManager:
def __init__(self, assets_dir: str = "assets") -> None:
self.assets_dir = assets_dir
self.images: Dict[str, pygame.Surface] = {}
self.config = self.load_config()
self.load_all_images()
def load_config(self) -> Dict:
"""加载素材配置文件"""
config_path = os.path.join(self.assets_dir, "config.json")
default_config = {
"player": "player.png",
"wall": "wall.png",
"box": "box.png",
"box_on_target": "box_on_target.png",
"target": "target.png",
"background": "background.png",
"menu_background": "menu_background.png",
"button": "button.png",
"button_hover": "button_hover.png"
}
try:
if os.path.exists(config_path):
with open(config_path, "r", encoding="utf-8") as f:
return json.load(f)
else:
# 创建默认配置文件
os.makedirs(self.assets_dir, exist_ok=True)
with open(config_path, "w", encoding="utf-8") as f:
json.dump(default_config, f, indent=4)
return default_config
except Exception as e:
print(f"加载配置文件失败: {e}")
return default_config
def load_image(self, asset_name: str, default_size: Tuple[int, int] = (TILE_SIZE, TILE_SIZE)) -> pygame.Surface:
"""加载单个图像,若失败则返回默认图形"""
asset_filename = self.config.get(asset_name, "")
if not asset_filename:
return self.create_default_surface(size=default_size, asset_name=asset_name)
asset_path = os.path.join(self.assets_dir, asset_filename)
try:
if os.path.exists(asset_path):
# 使用pygame.image.load加载图像
image = pygame.image.load(asset_path)
# 检查图像是否有alpha通道
if image.get_alpha() is None:
image = image.convert() # 优化无透明通道的图像
else:
image = image.convert_alpha() # 优化有透明通道的图像
# 调整图像大小
return pygame.transform.scale(image, default_size)
else:
print(f"图像文件不存在: {asset_path}")
return self.create_default_surface(size=default_size, asset_name=asset_name)
except Exception as e:
print(f"加载图像失败: {e}")
return self.create_default_surface(size=default_size, asset_name=asset_name)
def load_all_images(self) -> None:
"""加载所有游戏图像"""
# 加载玩家图像
self.images["player"] = self.load_image("player", (PLAYER_SIZE, PLAYER_SIZE))
# 加载游戏元素图像
for element in ["wall", "box", "box_on_target", "target"]:
self.images[element] = self.load_image(element)
# 加载背景和菜单图像
self.images["background"] = self.load_image("background", (SCREEN_WIDTH, SCREEN_HEIGHT))
self.images["menu_background"] = self.load_image("menu_background", (SCREEN_WIDTH, SCREEN_HEIGHT))
# 加载按钮图像
self.images["button"] = self.load_image("button", (200, 50))
self.images["button_hover"] = self.load_image("button_hover", (200, 50))
def create_default_surface(self, size: Tuple[int, int], asset_name: str) -> pygame.Surface:
"""创建默认图形"""
surface = pygame.Surface(size, pygame.SRCALPHA)
if asset_name == "player":
surface.fill(PLAYER_COLOR)
# 简单的人脸标记
pygame.draw.circle(surface, WHITE, (size[0] // 2, size[1] // 3), size[0] // 10)
pygame.draw.circle(surface, WHITE, (size[0] // 2 + size[0] // 5, size[1] // 3), size[0] // 10)
elif asset_name == "wall":
surface.fill(WALL_COLOR)
elif asset_name == "box":
surface.fill(BOX_COLOR)
elif asset_name == "box_on_target":
surface.fill(BOX_ON_TARGET_COLOR)
elif asset_name == "target":
surface.fill(TARGET_COLOR)
elif asset_name == "background":
surface.fill(BACKGROUND_COLOR)
elif "button" in asset_name:
surface.fill(BUTTON_COLOR if "hover" not in asset_name else BUTTON_HOVER_COLOR)
pygame.draw.rect(surface, BLACK, (0, 0, size[0], size[1]), 2)
else:
surface.fill(ERROR_COLOR)
error_text = tiny_font.render("ERROR", True, WHITE)
surface.blit(error_text, (size[0] // 2 - error_text.get_width() // 2,
size[1] // 2 - error_text.get_height() // 2))
return surface
def get_image(self, asset_name: str) -> pygame.Surface:
"""获取图像,若不存在则返回默认"""
return self.images.get(asset_name, self.create_default_surface((TILE_SIZE, TILE_SIZE), asset_name))
这是我用到的图片






对游戏主体代码的实现
# 玩家角色类
class Player:
def __init__(self, x: int, y: int, asset_manager: AssetManager) -> None:
self.x = x
self.y = y
self.asset_manager = asset_manager
def move(self, direction: Tuple[int, int]) -> None:
"""直接移动玩家位置"""
self.x += direction[0]
self.y += direction[1]
def draw(self, screen: pygame.Surface, offset_x: int, offset_y: int) -> None:
"""绘制玩家"""
# 计算居中位置
x_pos = offset_x + self.x * TILE_SIZE
y_pos = offset_y + self.y * TILE_SIZE
# 绘制玩家图像
screen.blit(self.asset_manager.get_image("player"), (x_pos, y_pos))
# 推箱子游戏类
class SokobanGame:
def __init__(self, asset_manager: AssetManager) -> None:
self.asset_manager = asset_manager
self.current_level = 0
self.reset_level()
self.moves = 0
self.history = [] # 用于撤销操作
self.state = "playing" # playing, level_complete, game_complete
self.confetti = Confetti() # 创建撒花效果实例
self.show_confetti = False # 是否显示撒花效果
def load_level(self, level_index: int) -> None:
level_data = levels[level_index]
self.walls = set()
self.boxes = set()
self.targets = set()
player_x, player_y = 0, 0
for y, row in enumerate(level_data):
for x, char in enumerate(row):
if char == '#':
self.walls.add((x, y))
elif char == '$':
self.boxes.add((x, y))
elif char == '.':
self.targets.add((x, y))
elif char == '@':
player_x, player_y = x, y
elif char == '*': # 箱子在目标上
self.boxes.add((x, y))
self.targets.add((x, y))
elif char == '+': # 玩家在目标上
player_x, player_y = x, y
self.targets.add((x, y))
# 创建玩家角色
self.player = Player(player_x, player_y, self.asset_manager)
def reset_level(self) -> None:
self.load_level(self.current_level)
self.moves = 0
self.history = []
self.state = "playing"
self.show_confetti = False # 重置关卡时不显示撒花
def move_player(self, direction: Tuple[int, int]) -> bool:
if self.state != "playing":
return False
# 保存当前状态用于撤销
self.history.append((self.player.x, self.player.y, self.boxes.copy(), self.moves))
new_x = self.player.x + direction[0]
new_y = self.player.y + direction[1]
# 检查是否可以移动
if (new_x, new_y) in self.walls:
self.history.pop() # 移除无效的历史记录
return False
# 检查是否推箱子
if (new_x, new_y) in self.boxes:
box_new_x = new_x + direction[0]
box_new_y = new_y + direction[1]
# 检查箱子是否可以移动
if (box_new_x, box_new_y) in self.walls or (box_new_x, box_new_y) in self.boxes:
self.history.pop() # 移除无效的历史记录
return False
# 移动箱子
self.boxes.remove((new_x, new_y))
self.boxes.add((box_new_x, box_new_y))
# 移动玩家
self.player.move(direction)
self.moves += 1
# 检查关卡是否完成
if self.is_level_complete():
self.state = "level_complete"
self.show_confetti = True # 关卡完成时显示撒花
self.confetti.reset() # 重置撒花效果
return True
def undo_move(self) -> bool:
if self.state != "playing" or not self.history:
return False
self.player.x, self.player.y, self.boxes, self.moves = self.history.pop()
return True
def is_level_complete(self) -> bool:
for box in self.boxes:
if box not in self.targets:
return False
return True
def next_level(self) -> bool:
if self.current_level < len(levels) - 1:
self.current_level += 1
self.reset_level()
return True
else:
self.state = "game_complete"
self.show_confetti = True # 游戏完成时显示撒花
self.confetti.reset() # 重置撒花效果
return False
def draw(self, screen: pygame.Surface) -> None:
# 绘制背景
screen.blit(self.asset_manager.get_image("background"), (0, 0))
# 计算偏移量以使游戏居中显示
max_x = max(max(x for x, y in self.walls), self.player.x, max(x for x, y in self.boxes))
max_y = max(max(y for x, y in self.walls), self.player.y, max(y for x, y in self.boxes))
offset_x = (SCREEN_WIDTH - (max_x + 1) * TILE_SIZE) // 2
offset_y = (SCREEN_HEIGHT - (max_y + 1) * TILE_SIZE) // 2
# 绘制目标点
for x, y in self.targets:
rect = pygame.Rect(offset_x + x * TILE_SIZE, offset_y + y * TILE_SIZE, TILE_SIZE, TILE_SIZE)
screen.blit(self.asset_manager.get_image("target"), rect)
# 绘制墙壁
for x, y in self.walls:
rect = pygame.Rect(offset_x + x * TILE_SIZE, offset_y + y * TILE_SIZE, TILE_SIZE, TILE_SIZE)
screen.blit(self.asset_manager.get_image("wall"), rect)
# 绘制箱子
for box in self.boxes:
x, y = box
rect = pygame.Rect(offset_x + x * TILE_SIZE, offset_y + y * TILE_SIZE, TILE_SIZE, TILE_SIZE)
# 根据箱子是否在目标点上选择不同的图像
image_key = "box_on_target" if box in self.targets else "box"
screen.blit(self.asset_manager.get_image(image_key), rect)
# 绘制玩家
self.player.draw(screen, offset_x, offset_y)
# 显示当前关卡和移动次数
level_text = small_font.render(f"关卡: {self.current_level + 1}/{len(levels)}", True, BLACK)
moves_text = small_font.render(f"移动次数: {self.moves}", True, BLACK)
screen.blit(level_text, (10, 10))
screen.blit(moves_text, (10, 40))
# 显示操作说明
controls_text = tiny_font.render(
"↑↓←→:移动 R:重置关卡 U:撤销 N:下一关 ESC:菜单", True, BLACK)
screen.blit(controls_text, (10, SCREEN_HEIGHT - 20))
# 如果关卡完成,显示消息
if self.state == "level_complete":
if self.current_level == len(levels) - 1:
message = "恭喜你通关了所有关卡!"
else:
message = "关卡完成!按 N 进入下一关"
# 创建半透明背景
s = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT), pygame.SRCALPHA)
s.fill((0, 0, 0, 128))
screen.blit(s, (0, 0))
# 显示消息
text = font.render(message, True, WHITE)
text_rect = text.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2 - 30))
screen.blit(text, text_rect)
# 显示移动次数
moves_msg = f"本关移动次数: {self.moves}"
moves_text = small_font.render(moves_msg, True, WHITE)
moves_rect = moves_text.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2 + 20))
screen.blit(moves_text, moves_rect)
# 显示继续提示
continue_text = small_font.render("按 R 重新开始本关", True, WHITE)
continue_rect = continue_text.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2 + 70))
screen.blit(continue_text, continue_rect)
# 如果游戏完成,显示消息
if self.state == "game_complete":
# 创建半透明背景
s = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT), pygame.SRCALPHA)
s.fill((0, 0, 0, 128))
screen.blit(s, (0, 0))
# 显示消息
text = font.render("恭喜你通关了所有关卡!", True, WHITE)
text_rect = text.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2 - 30))
screen.blit(text, text_rect)
# 显示总移动次数
total_moves = sum(len(level) for level in levels)
moves_msg = f"总移动次数: {self.moves}"
moves_text = small_font.render(moves_msg, True, WHITE)
moves_rect = moves_text.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2 + 20))
screen.blit(moves_text, moves_rect)
# 显示继续提示
continue_text = small_font.render("按 R 重新开始游戏", True, WHITE)
continue_rect = continue_text.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2 + 70))
screen.blit(continue_text, continue_rect)
# 更新并绘制撒花效果
if self.show_confetti:
self.confetti.update()
self.confetti.draw(screen)
# 游戏菜单类
class GameMenu:
def __init__(self, asset_manager: AssetManager) -> None:
self.asset_manager = asset_manager
self.buttons = []
self.create_buttons()
def create_buttons(self) -> None:
# 创建开始游戏按钮
start_button = {
"rect": pygame.Rect(SCREEN_WIDTH // 2 - 100, SCREEN_HEIGHT // 2 - 80, 200, 50),
"text": "开始游戏",
"action": "start"
}
# 创建关卡选择按钮
levels_button = {
"rect": pygame.Rect(SCREEN_WIDTH // 2 - 100, SCREEN_HEIGHT // 2 - 20, 200, 50),
"text": "选择关卡",
"action": "levels"
}
# 创建退出按钮
exit_button = {
"rect": pygame.Rect(SCREEN_WIDTH // 2 - 100, SCREEN_HEIGHT // 2 + 40, 200, 50),
"text": "退出游戏",
"action": "exit"
}
self.buttons = [start_button, levels_button, exit_button]
def handle_event(self, event: pygame.event.Event) -> Optional[str]:
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1: # 左键点击
for button in self.buttons:
if button["rect"].collidepoint(event.pos):
return button["action"]
return None
def draw(self, screen: pygame.Surface) -> None:
# 绘制背景
screen.blit(self.asset_manager.get_image("menu_background"), (0, 0))
# 绘制标题
title_text = font.render("推箱子游戏", True, BLACK)
title_rect = title_text.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2 - 150))
screen.blit(title_text, title_rect)
# 绘制作者和版本信息
info_text = tiny_font.render("作者: 怀素 | 版本: 1.0", True, BLACK)
info_rect = info_text.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT - 30))
screen.blit(info_text, info_rect)
# 绘制按钮
for button in self.buttons:
# 检查鼠标是否悬停在按钮上
button_image = self.asset_manager.get_image(
"button_hover" if button["rect"].collidepoint(pygame.mouse.get_pos()) else "button")
# 绘制按钮
screen.blit(button_image, button["rect"])
# 绘制按钮文字
text = small_font.render(button["text"], True, BLACK)
text_rect = text.get_rect(center=button["rect"].center)
screen.blit(text, text_rect)
# 关卡选择菜单类
class LevelSelectMenu:
def __init__(self, asset_manager: AssetManager) -> None:
self.asset_manager = asset_manager
self.buttons = []
self.back_button = {
"rect": pygame.Rect(50, SCREEN_HEIGHT - 70, 150, 50),
"text": "返回主菜单",
"action": "back"
}
self.create_level_buttons()
def create_level_buttons(self) -> None:
self.buttons = []
for i in range(len(levels)):
row = i // 3
col = i % 3
button = {
"rect": pygame.Rect(SCREEN_WIDTH // 2 - 200 + col * 150,
SCREEN_HEIGHT // 2 - 100 + row * 80, 120, 60),
"text": f"关卡 {i + 1}",
"action": "level_" + str(i)
}
self.buttons.append(button)
def handle_event(self, event: pygame.event.Event) -> Tuple[Optional[str], Optional[int]]:
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1: # 左键点击
for button in self.buttons:
if button["rect"].collidepoint(event.pos):
level_index = int(button["action"].split("_")[1])
return ("start_level", level_index)
if self.back_button["rect"].collidepoint(event.pos):
return ("back", None)
return (None, None)
def draw(self, screen: pygame.Surface) -> None:
# 绘制背景
screen.blit(self.asset_manager.get_image("menu_background"), (0, 0))
# 绘制标题
title_text = font.render("选择关卡", True, BLACK)
title_rect = title_text.get_rect(center=(SCREEN_WIDTH // 2, 100))
screen.blit(title_text, title_rect)
# 绘制关卡按钮
for button in self.buttons:
# 检查鼠标是否悬停在按钮上
button_image = self.asset_manager.get_image(
"button_hover" if button["rect"].collidepoint(pygame.mouse.get_pos()) else "button")
# 绘制按钮
screen.blit(button_image, button["rect"])
# 绘制按钮文字
text = small_font.render(button["text"], True, BLACK)
text_rect = text.get_rect(center=button["rect"].center)
screen.blit(text, text_rect)
# 绘制返回按钮
back_image = self.asset_manager.get_image(
"button_hover" if self.back_button["rect"].collidepoint(pygame.mouse.get_pos()) else "button")
screen.blit(back_image, self.back_button["rect"])
back_text = small_font.render(self.back_button["text"], True, BLACK)
back_text_rect = back_text.get_rect(center=self.back_button["rect"].center)
screen.blit(back_text, back_text_rect)
主函数代码
def main() -> None:
# 创建素材管理器
asset_manager = AssetManager()
# 创建游戏组件
game = SokobanGame(asset_manager)
main_menu = GameMenu(asset_manager)
level_select = LevelSelectMenu(asset_manager)
# 游戏状态
state = "menu" # menu, level_select, playing
running = True
while running:
# 处理事件
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if state == "menu":
action = main_menu.handle_event(event)
if action == "start":
game.reset_level()
state = "playing"
elif action == "levels":
state = "level_select"
elif action == "exit":
running = False
elif state == "level_select":
action, level_index = level_select.handle_event(event)
if action == "start_level":
game.current_level = level_index
game.reset_level()
state = "playing"
elif action == "back":
state = "menu"
elif state == "playing":
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
game.move_player(UP)
elif event.key == pygame.K_DOWN:
game.move_player(DOWN)
elif event.key == pygame.K_LEFT:
game.move_player(LEFT)
elif event.key == pygame.K_RIGHT:
game.move_player(RIGHT)
elif event.key == pygame.K_r:
game.reset_level()
game.show_confetti = False # 重置时关闭撒花
elif event.key == pygame.K_n:
if game.state == "level_complete":
game.next_level()
if game.state == "game_complete":
state = "menu"
elif event.key == pygame.K_u:
game.undo_move()
elif event.key == pygame.K_ESCAPE:
state = "menu"
game.show_confetti = False # 返回菜单时关闭撒花
# 如果关卡完成,按N进入下一关
if game.state == "level_complete" and event.type == pygame.KEYDOWN and event.key == pygame.K_n:
if not game.next_level():
state = "menu"
game.show_confetti = False # 返回菜单时关闭撒花
# 如果游戏完成,按R重新开始
if game.state == "game_complete" and event.type == pygame.KEYDOWN and event.key == pygame.K_r:
game.reset_level()
state = "playing"
game.show_confetti = False # 重新开始时关闭撒花
# 绘制当前状态
if state == "menu":
main_menu.draw(screen)
elif state == "level_select":
level_select.draw(screen)
elif state == "playing":
game.draw(screen)
# 更新显示
pygame.display.flip()
# 控制帧率
clock.tick(FPS)
pygame.quit()
sys.exit()
if __name__ == "__main__":
main()
实验结果展示



代码托管到码云
https://gitee.com/jun-huaisu/pythonwork/blob/master/推箱子.py
实验中遇到的问题及解决办法
一、设置游戏关卡
在一开始时,我希望能够让python自己生成关卡模式,但是生成的太随机,而且很多变量都不太好控制,当然主要还是代码设计难度太高了,所以我就采用了一个好用问题也很少的笨办法,那就是自己手动设置(手动狗头)
二、对于素材的引入
在一开始添加素材进推箱子代码文件夹中时,老是由于尺寸问题导致图片解析错误,之后又因为代码部分细节的设计错误,浪费了很多时间,好在在同学和ai查错的帮助下,还是解决了这一问题
三、添加动画帧
因为使用动画帧时,没太能理解人物动画帧加载逻辑self.asset_manager.images.get("player_down") 没拿到动画帧,就会用 self.asset_manager.get_image("player") ,但要是 get_image 也没正确返回,就总画不出游戏人物,这一问题也卡了我很久(苦笑)
四、代码运行错误
这个问题的解决主要就是根据python上的报错提示一遍遍的改就行了
收获与心得体会

就借老师这句话,也祝老师万事顺意,马到成功!
同时,感谢老师这一学期以来的陪伴和辛勤付出,真的感觉自己向你学到了很多东西,python实在太权威了,很多问题都能从python里找到解决的办法,虽然这学期的python课结束了,但我还好继续学习python,到时候有不会的还找您哈。最后再说一句:强哥,YYDS!
参考资料
《Python 编程从入门到实践》
deepseek
https://docs.python.org/
视频链接
https://t.bilibili.com/1076447567541174311?share_source=pc_native

浙公网安备 33010602011771号