import tkinter as tk
from tkinter import messagebox, ttk # 导入ttk模块用于创建Combobox
import random
class SnakeGame:
def __init__(self, master):
self.master = master
self.master.title("贪吃蛇游戏")
self.master.geometry("400x520") # 设置初始窗口大小
self.master.resizable(True, True) # 允许窗口调整大小
# 创建控制面板框架
control_frame = tk.Frame(self.master)
control_frame.pack(fill=tk.X, pady=5) # 填充整个宽度
self.score_label = tk.Label(control_frame, text="得分: 0", font=("Arial", 12))
self.score_label.pack(side=tk.LEFT, padx=20)
# 添加暂停按钮
self.pause_button = tk.Button(
control_frame,
text="暂停",
command=self.toggle_pause,
width=8,
state=tk.DISABLED # 初始状态下禁用暂停按钮
)
self.pause_button.pack(side=tk.RIGHT, padx=20)
# 添加开始按钮
self.start_button = tk.Button(
control_frame,
text="开始",
command=self.start_game,
width=8
)
self.start_button.pack(side=tk.RIGHT, padx=20)
# 使用ttk.Combobox创建速度调节菜单
self.speed_var = tk.StringVar(value="中等")
speed_options = ["慢速", "中等", "快速"]
self.speed_menu = ttk.Combobox(control_frame, textvariable=self.speed_var, values=speed_options,
state='readonly', width=8)
self.speed_menu.bind('<<ComboboxSelected>>', self.set_speed) # 绑定选择事件
self.speed_menu.bind("<KeyPress>", self.ignore_keypress) # 禁用游戏运行时的键盘导航
self.speed_menu.pack(side=tk.RIGHT, padx=20)
# 创建游戏区域框架
game_frame = tk.Frame(self.master)
game_frame.pack(expand=True, fill=tk.BOTH) # 扩展并填充剩余空间
self.canvas = tk.Canvas(game_frame, bg="black", width=400, height=400)
self.canvas.pack(expand=True, fill=tk.BOTH) # 扩展并填充剩余空间
# 初始化游戏状态变量
self.snake = [(100, 100), (80, 100), (60, 100)]
self.food = None
self.direction = "Right"
self.score = 0
self.paused = False # 新增暂停状态
self.game_started = False # 标记游戏是否已经开始
self.speed = 100 # 初始速度为100毫秒每帧
# 绑定键盘事件
self.master.bind("<KeyPress>", self.change_direction)
self.canvas.focus_set()
# 添加署名标签
self.signature_label = tk.Label(self.master, text="© 2025 程序员姓名", fg="gray", font=("Arial", 10))
self.signature_label.pack(side=tk.BOTTOM, pady=5) # 将署名标签放置在窗口底部
# 监听窗口大小变化
self.master.bind("<Configure>", self.on_resize)
def start_game(self):
if not self.game_started:
self.game_started = True
self.food = self.create_food() # 在游戏开始时生成食物
self.score = 0
self.score_label.config(text=f"得分: {self.score}")
self.start_button.config(state=tk.DISABLED) # 禁用开始按钮
self.pause_button.config(state=tk.NORMAL) # 启用暂停按钮
self.canvas.focus_set() # 确保焦点回到画布上
self.game_loop() # 开始游戏循环
def set_speed(self, event):
value = self.speed_var.get()
if value == "慢速":
self.speed = 150
elif value == "中等":
self.speed = 100
elif value == "快速":
self.speed = 50
# 移除吃食物时的速度调整逻辑(在move_snake方法中)
def create_food(self):
while True:
x = random.randint(0, int(self.canvas.winfo_width() / 10) - 1) * 10
y = random.randint(0, int(self.canvas.winfo_height() / 10) - 1) * 10
if (x, y) not in self.snake:
return self.canvas.create_rectangle(x, y, x + 10, y + 10, fill="red")
def ignore_keypress(self, event):
"""忽略在游戏运行时 Combobox 上的按键事件"""
if self.game_started and not self.paused:
return "break" # 阻止事件进一步传播
def change_direction(self, event):
if self.paused: # 暂停时禁止改变方向
return
key = event.keysym
if key in ["Up", "Down", "Left", "Right"]:
if (key == "Up" and self.direction != "Down" or
key == "Down" and self.direction != "Up" or
key == "Left" and self.direction != "Right" or
key == "Right" and self.direction != "Left"):
self.direction = key
self.canvas.focus_set() # 确保焦点回到画布上
def move_snake(self):
head_x, head_y = self.snake[0]
if self.direction == "Up":
new_head = (head_x, head_y - 10)
elif self.direction == "Down":
new_head = (head_x, head_y + 10)
elif self.direction == "Left":
new_head = (head_x - 10, head_y)
else:
new_head = (head_x + 10, head_y)
# 实现穿墙效果
canvas_width = self.canvas.winfo_width()
canvas_height = self.canvas.winfo_height()
new_head = (
new_head[0] % canvas_width, # X坐标超出范围时回到另一边
new_head[1] % canvas_height # Y坐标超出范围时回到另一边
)
# 自身碰撞检测
if new_head in self.snake[1:]:
self.game_over()
return
self.snake.insert(0, new_head)
# 吃食物检测
food_coords = self.canvas.coords(self.food)
if (new_head[0] == food_coords[0] and new_head[1] == food_coords[1]):
self.score += 1
self.score_label.config(text=f"得分: {self.score}")
self.canvas.delete(self.food)
self.food = self.create_food()
self.speed = max(20, self.speed - 5) # 提高游戏速度
else:
self.snake.pop()
self.draw_snake()
def draw_snake(self):
self.canvas.delete("snake")
for x, y in self.snake:
self.canvas.create_rectangle(x, y, x + 10, y + 10, fill="green", tags="snake")
def game_loop(self):
if self.game_started and not self.paused: # 根据暂停状态决定是否移动
self.move_snake()
self.master.after(self.speed, self.game_loop) # 使用当前速度值
def toggle_pause(self):
"""切换暂停/继续状态"""
self.paused = not self.paused
self.pause_button.config(text="继续" if self.paused else "暂停")
if not self.paused:
self.canvas.focus_set() # 恢复焦点以便接收键盘事件
def game_over(self):
self.canvas.delete("all")
answer = messagebox.askyesno("游戏结束", f"得分: {self.score}\n重新开始?")
if answer:
self.reset_game() # 重置游戏状态
else:
self.master.destroy()
def reset_game(self):
"""重置游戏状态"""
self.snake = [(100, 100), (80, 100), (60, 100)]
self.food = None
self.direction = "Right"
self.score = 0
self.paused = False
self.game_started = False
self.speed = 100
self.score_label.config(text="得分: 0")
self.start_button.config(state=tk.NORMAL)
self.pause_button.config(state=tk.DISABLED)
self.game_loop()
def on_resize(self, event):
if event.widget == self.master:
# 调整画布尺寸为10的倍数
new_width = event.width - (event.width % 10)
new_height = event.height - (event.height % 10)
self.canvas.config(width=new_width, height=new_height)
# 更新蛇的位置
self.snake = [(x % new_width, y % new_height) for x, y in self.snake]
self.draw_snake()
# 重新生成食物
if self.food is not None:
self.canvas.delete(self.food)
self.food = self.create_food()
if __name__ == "__main__":
root = tk.Tk()
game = SnakeGame(root)
root.mainloop()
贪吃蛇程序
于 2025-01-31 13:15:26 首次发布
1460

被折叠的 条评论
为什么被折叠?



