Python Tkinter贪吃蛇游戏故障:苹果不显示、蛇身异常增长
解决你的Tkinter贪吃蛇问题:苹果不显示与蛇身增长异常
嘿,我仔细看了你的代码,找到了导致你遇到的两个问题的根源,咱们一步步来修复:
问题1:苹果生成后画布上看不到
你的apple_make函数里有三个明显的问题:
- 你用
create_line画苹果时,起点和终点是同一个坐标,这样画出来的线长度为0,当然看不到!换用create_oval画圆形苹果更符合预期,也能正常显示。 apple_y1被硬编码成了10,没有随机生成y坐标,就算能显示,苹果也只会固定在顶部。- 没有删除之前的苹果,多次生成后会有多个苹果留在画布上。
修复后的apple_make函数:
def apple_make(self): global apple_x1, apple_y1 # 先删掉之前的苹果,给苹果加个固定标签方便操作 can.delete("apple") # 生成和蛇身对齐的随机坐标(必须是etch_len的倍数,不然蛇永远吃不到苹果) apple_x1 = random.randint(10, 59) * etch_len apple_y1 = random.randint(10, 59) * etch_len # 画一个红色圆形苹果 can.create_oval(apple_x1-5, apple_y1-5, apple_x1+5, apple_y1+5, fill="red", tag="apple")
问题2:蛇身增长需要多次移动,且次数递增
这个问题有两个核心原因:
- 拼写错误:
move_down函数里的条件判断写的是y3==apple,这里应该是apple_y1!导致向下移动时吃到苹果根本不会触发增长,只有其他方向才会,这会让你误以为增长延迟。 - 逻辑错误:你当前的逻辑是每次移动都添加一段蛇身,然后删除最旧的一段。就算吃到苹果增加了
body_len,remove_last还是会执行,相当于这次移动加了一段又删了一段,蛇身并没有立刻变长。后续remove_last会因为body_len变大,删除更早的标签,导致需要多次移动才能体现出增长,而且每次增长后需要多移动一次。
正确的逻辑应该是:吃到苹果时,只加新段不删旧段;没吃到时,加新段同时删旧段。
以move_up为例,修改后的代码:
def move_up(self): global x3, y3, num, apple_x1, apple_y1, body_len num += 1 tag = str(num) # 先添加新的蛇身段 can.create_line(x3, y3, x3, y3-etch_len, width=etch_wid, fill=colour[0], tag=tag) body_tags.append(tag) # 用列表存蛇身标签,更易管理 y3 -= etch_len # 判断是否吃到苹果 if x3 == apple_x1 and y3 == apple_y1: body_len += 1 apple_make(self) else: # 没吃到才删除最后一段 remove_last()
另外,我给你加了一个body_tags列表来存储蛇身的标签,代替原来用num计算的方式,这样删除最旧段的逻辑更清晰,避免计算错误:
# 全局定义列表 body_tags = [] # remove_last函数修改为 def remove_last(): if len(body_tags) > body_len: old_tag = body_tags.pop(0) can.delete(old_tag)
额外优化:初始化蛇身
原来的代码没有初始化蛇身,一开始蛇只有一段,我加了初始化代码,让游戏开始时就有设定长度的蛇:
# 初始化蛇身 for i in range(body_len): tag = str(num) can.create_line(x3, y3 + i*etch_len, x3, y3 + (i+1)*etch_len, width=etch_wid, fill=colour[0], tag=tag) body_tags.append(tag) num += 1
完整修复后的代码
from tkinter import * import random window = Tk() window.title("snake") window.geometry("600x600") can = Canvas(window, height=600, width=600, background="white") can.pack() # 全局变量 num = 1 x3 = 100 y3 = 100 etch_len = 10 etch_wid = 10 body_len = 2 apple_x1 = 0 apple_y1 = 0 colour = ["black"] body_tags = [] # 存储蛇身标签的列表,方便管理 # 初始化蛇身 for i in range(body_len): tag = str(num) can.create_line(x3, y3 + i*etch_len, x3, y3 + (i+1)*etch_len, width=etch_wid, fill=colour[0], tag=tag) body_tags.append(tag) num += 1 def move_up(self): global x3, y3, num, apple_x1, apple_y1, body_len num += 1 tag = str(num) # 添加新的蛇身段 can.create_line(x3, y3, x3, y3 - etch_len, width=etch_wid, fill=colour[0], tag=tag) body_tags.append(tag) y3 -= etch_len # 判断是否吃到苹果 if x3 == apple_x1 and y3 == apple_y1: body_len += 1 apple_make(self) else: remove_last() def move_down(self): global x3, y3, num, apple_x1, apple_y1, body_len num += 1 tag = str(num) # 添加新的蛇身段 can.create_line(x3, y3, x3, y3 + etch_len, width=etch_wid, fill=colour[0], tag=tag) body_tags.append(tag) y3 += etch_len # 修复拼写错误:apple -> apple_y1 if x3 == apple_x1 and y3 == apple_y1: body_len += 1 apple_make(self) else: remove_last() def move_left(self): global x3, y3, num, apple_x1, apple_y1, body_len num += 1 tag = str(num) # 添加新的蛇身段 can.create_line(x3, y3, x3 - etch_len, y3, width=etch_wid, fill=colour[0], tag=tag) body_tags.append(tag) x3 -= etch_len if x3 == apple_x1 and y3 == apple_y1: body_len += 1 apple_make(self) else: remove_last() def move_right(self): global x3, y3, num, apple_x1, apple_y1, body_len num += 1 tag = str(num) # 添加新的蛇身段 can.create_line(x3, y3, x3 + etch_len, y3, width=etch_wid, fill=colour[0], tag=tag) body_tags.append(tag) x3 += etch_len if x3 == apple_x1 and y3 == apple_y1: body_len += 1 apple_make(self) else: remove_last() def remove_last(): # 删除最旧的蛇身段,保持蛇身长度为body_len if len(body_tags) > body_len: old_tag = body_tags.pop(0) can.delete(old_tag) def apple_make(self): global apple_x1, apple_y1 # 删除之前的苹果 can.delete("apple") # 生成与蛇身对齐的随机坐标(10的倍数) apple_x1 = random.randint(10, 59) * etch_len apple_y1 = random.randint(10, 59) * etch_len # 绘制圆形苹果 can.create_oval(apple_x1-5, apple_y1-5, apple_x1+5, apple_y1+5, fill="red", tag="apple") # 绑定按键事件 window.bind("w", move_up) window.bind("s", move_down) window.bind("a", move_left) window.bind("d", move_right) window.bind("<Up>", apple_make) # 游戏开始时生成第一个苹果 apple_make(None) window.mainloop()
现在运行这个代码,苹果会正常显示,蛇吃到苹果后会立刻增长,不会再有延迟的问题啦!
内容的提问来源于stack exchange,提问作者Alex fradle
相关产品推荐
相关产品推荐

