用 Python 实现一个可视化的推箱子游戏,这是一个很经典的编程练习,既能锻炼逻辑思维,也能学习图形界面编程。

使用 Python 内置的 tkinter 库来实现这个游戏,它不需要额外安装,简单易用,非常适合新手入门图形界面开发。
import tkinter as tk
from tkinter import messagebox
classSokobanGame:
def__init__(self, root):
# 游戏基本设置
self.root = root
self.root.title("推箱子游戏")
# 每个格子的大小(像素)
self.cell_size = 60
# 定义游戏元素的颜色
self.colors = {
'wall': '#8B4513', # 墙 - 棕色
'floor': '#F5DEB3', # 空地 - 小麦色
'box': '#FFD700', # 箱子 - 金色
'target': '#FF6347', # 目标点 - 番茄红
'player': '#4169E1'# 玩家 - 皇家蓝
}
# 定义游戏地图 (0=空地, 1=墙, 2=箱子, 3=目标点, 4=玩家)
self.map = [
[1, 1, 1, 1, 1, 1, 1],
[1, 0, 0, 0, 0, 0, 1],
[1, 0, 2, 0, 2, 0, 1],
[1, 0, 0, 2, 0, 0, 1],
[1, 0, 3, 0, 3, 0, 1],
[1, 0, 3, 0, 0, 4, 1],
[1, 1, 1, 1, 1, 1, 1]
]
# 找到玩家初始位置
self.player_x, self.player_y = self.find_player()
# 创建画布
self.canvas = tk.Canvas(
root,
width=len(self.map[0])*self.cell_size,
height=len(self.map)*self.cell_size
)
self.canvas.pack()
# 绑定键盘事件
self.root.bind('<KeyPress>', self.on_key_press)
# 绘制初始游戏界面
self.draw_game()
deffind_player(self):
"""找到玩家在地图中的初始位置"""
for y, row in enumerate(self.map):
for x, cell in enumerate(row):
if cell == 4:
return x, y
return0, 0
defdraw_cell(self, x, y, color):
"""绘制单个格子"""
x1 = x * self.cell_size
y1 = y * self.cell_size
x2 = x1 + self.cell_size
y2 = y1 + self.cell_size
self.canvas.create_rectangle(x1, y1, x2, y2, fill=color, outline='black', width=2)
defdraw_game(self):
"""绘制整个游戏界面"""
self.canvas.delete('all') # 清空画布
# 绘制地图
for y, row in enumerate(self.map):
for x, cell in enumerate(row):
# 先绘制基础格子(墙或空地)
if cell == 1:
self.draw_cell(x, y, self.colors['wall'])
else:
self.draw_cell(x, y, self.colors['floor'])
# 绘制覆盖在上面的元素
if cell == 2: # 箱子
self.draw_cell(x, y, self.colors['box'])
elif cell == 3: # 目标点
# 目标点用圆形表示
center_x = x * self.cell_size + self.cell_size // 2
center_y = y * self.cell_size + self.cell_size // 2
radius = self.cell_size // 3
self.canvas.create_oval(
center_x - radius, center_y - radius,
center_x + radius, center_y + radius,
fill=self.colors['target']
)
elif cell == 4: # 玩家
# 玩家用正方形表示
center_x = x * self.cell_size + self.cell_size // 2
center_y = y * self.cell_size + self.cell_size // 2
half_size = self.cell_size // 4
self.canvas.create_rectangle(
center_x - half_size, center_y - half_size,
center_x + half_size, center_y + half_size,
fill=self.colors['player']
)
defmove_player(self, dx, dy):
"""处理玩家移动逻辑"""
# 计算新位置
new_x = self.player_x + dx
new_y = self.player_y + dy
# 检查新位置是否是墙
if self.map[new_y][new_x] == 1:
returnFalse
# 检查新位置是否是箱子
if self.map[new_y][new_x] == 2:
# 计算箱子要移动到的位置
box_new_x = new_x + dx
box_new_y = new_y + dy
# 检查箱子的新位置是否合法(不是墙也不是箱子)
if self.map[box_new_y][box_new_x] in (0, 3):
# 移动箱子
self.map[box_new_y][box_new_x] = 2
self.map[new_y][new_x] = 0# 清空原来箱子的位置
else:
returnFalse
# 移动玩家
self.map[self.player_y][self.player_x] = 0# 清空原来玩家的位置
self.map[new_y][new_x] = 4# 设置新位置为玩家
self.player_x, self.player_y = new_x, new_y
returnTrue
defcheck_win(self):
"""检查是否获胜(所有目标点都有箱子)"""
for y, row in enumerate(self.map):
for x, cell in enumerate(row):
# 如果还有空的目标点,说明还没赢
if cell == 3:
returnFalse
returnTrue
defon_key_press(self, event):
"""处理键盘按键事件"""
moved = False
# 根据按键方向移动
if event.keysym == 'Up':
moved = self.move_player(0, -1)
elif event.keysym == 'Down':
moved = self.move_player(0, 1)
elif event.keysym == 'Left':
moved = self.move_player(-1, 0)
elif event.keysym == 'Right':
moved = self.move_player(1, 0)
# 如果移动成功,重新绘制游戏界面
if moved:
self.draw_game()
# 检查是否获胜
if self.check_win():
messagebox.showinfo("恭喜", "你成功通关了!")
self.root.quit()
# 运行游戏
if __name__ == "__main__":
root = tk.Tk()
game = SokobanGame(root)
root.mainloop()
游戏初始化 (__init__):
核心方法:
find_player(): 查找玩家初始位置draw_cell() 和 draw_game(): 负责绘制游戏界面move_player(): 处理玩家移动逻辑,包括推箱子的碰撞检测check_win(): 判断是否所有箱子都推到目标点on_key_press(): 响应键盘按键,控制玩家上下左右移动游戏操作:
.py 文件中运行即可tkinter 实现可视化,核心是通过二维列表表示地图,监听键盘事件实现玩家移动。你可以根据自己的喜好修改地图布局(修改 self.map 二维列表)、调整颜色(修改 self.colors 字典)或格子大小(修改 self.cell_size)来定制游戏。