pyzyd 发表于 2025-5-8 23:53:45

tkinter制作的简易贪吃蛇

自己制作的第一个游戏!
import tkinter as tk
import random

class Game(tk.Tk):
    def __init__(self):
      tk.Tk.__init__(self)
      self.title('Eat Snake')
      # 固定边框
      self.resizable(False,False)
      # 设置边长、像素
      self.width = 15
      self.height = 16
      self.px = 20
      # 设置自动移动
      self.auto = True
      # 创建画布
      self.canvas = tk.Canvas(
            self, width=self.width*self.px,
            height=self.height*self.px)
      self.canvas.grid(row=0,column=0,columnspan=2)
      # 设置画布的点集(范围)
      self.canvas_set = set()
      for i in range(0, self.width):
            for j in range(0, self.height):
                self.canvas_set.add((i,j))
      # 绑定按键功能
      self.bind("<Key-Right>", self.move_right)
      self.bind("<Key-Left>", self.move_left)
      self.bind("<Key-Up>", self.move_up)
      self.bind("<Key-Down>", self.move_down)
      # 运行游戏
      self.run_game()

    def draw_rect(self,x,y,obj="bg"):
      """"绘制像素"""
      match obj:
            case 'bg':
                # 设置背景像素颜色
                fill = 'grey'
                outline = 'white'
            case 'snake':
                # 设置蛇身像素颜色
                fill = 'green'
                outline = 'red'
            case 'head':
                # 设置蛇头像素颜色
                fill = 'yellow'
                outline = 'red'
            case 'apple':
                # 设置Food像素颜色
                fill = 'red'
                outline = 'yellow'
      px = self.px
      try:
            # 绘制像素
            self.canvas.create_rectangle(
                x*px,y*px,
                (x+1)*px,(y+1)*px,
                fill=fill,outline=outline
            )
      except:
            # 如果fill和outline没有定义,打印Error
            print("Error")

    def initialize(self):
      """初始化界面"""
      # 绘制背景
      for x,y in list(self.canvas_set):
            self.draw_rect(x,y,obj='bg')
      # 绘制初始的贪吃蛇
      self.snake_list = [(self.width//2 + i,self.height//2) for i in range(3)]
      for (i, j) in self.snake_list:
            if (i,j) == self.snake_list[-1]:
                self.draw_rect(i,j,obj='head')
            else:
                self.draw_rect(i,j,obj='snake')
      # 绘制初始的Food
      self.food_set = self.canvas_set.difference(set(self.snake_list))
      self.food_x,self.food_y = random.choice(list(self.food_set))
      self.draw_rect(self.food_x,self.food_y,obj='apple')

    def flip(self,food=False):
      """刷新界面,使画面动起来"""
      # 删除画布上所有元素
      self.canvas.delete("all")
      # 重新绘制当前画布上的元素
      for (x,y) in list(self.canvas_set):
            self.draw_rect(x,y,obj='bg')
      for (i, j) in self.snake_list:
            if (i, j) == self.snake_list[-1]:
                self.draw_rect(i, j, obj='head')
            else:
                self.draw_rect(i, j, obj='snake')
      if food:
            self.food_set = self.canvas_set.difference(set(self.snake_list[-1]))
            self.food_x,self.food_y = random.choice(list(self.food_set))
      self.draw_rect(self.food_x, self.food_y, obj='apple')

    def move_right(self,event):
      x, y = self.snake_list[-1]
      if x <= self.snake_list[-2] and y == self.snake_list[-2]:
            pass
      else:
            self.run(1,0)

    def move_left(self,event):
      x, y = self.snake_list[-1]
      if x >= self.snake_list[-2] and y == self.snake_list[-2]:
            pass
      else:
            self.run(-1,0)

    def move_up(self,event):
      x, y = self.snake_list[-1]
      if x == self.snake_list[-2] and y >= self.snake_list[-2]:
            pass
      else:
            self.run(0,-1)

    def move_down(self,event):
      x, y = self.snake_list[-1]
      if x == self.snake_list[-2] and y <= self.snake_list[-2]:
            pass
      else:
            self.run(0,1)

    def run(self,move_x,move_y):
      x, y = self.snake_list[-1]
      food = self.eat_food(x + move_x, y + move_y)
      if food == False:
            self.snake_list.pop(0)
      else:
            self.food_x, self.food_y = random.choice(list(self.food_set))
            print(self.food_x, self.food_y)# 无意义,可删去
      if move_x != 0 or move_y != 0:
            self.snake_list.append((x + move_x, y + move_y))
      if self.is_over(x + move_x, y + move_y):
            self.game_over()
      else:
            self.flip(food)

    def eat_food(self,x,y):
      if x == self.food_x and y == self.food_y:
            return True
      else:
            return False

    def is_over(self,x,y):
      ls = len(self.snake_list)
      if x < 0 or y < 0 or x >= self.width or y >= self.height:
            return True
      elif (x, y) in self.snake_list[:ls-1]:
            return True
      return False

    def again(self):
      self.destroy()
      self.__init__()

    def game_over(self):
      w = self.width*self.px // 2
      h = self.height*self.px // 2
      self.canvas.create_text(w, h, text="GAME OVER", fill="red", font=("黑体",50))
      qb = tk.Button(self,text="QUIT", font=50, command=self.destroy)
      qb.grid(row=1,column=0,sticky="nsew")
      rb = tk.Button(self,text="Again", font=50, command=self.again)
      rb.grid(row=1,column=1,sticky="nsew")
      self.unbind("<Key-Right>")
      self.unbind("<Key-Left>")
      self.unbind("<Key-Up>")
      self.unbind("<Key-Down>")
      self.auto = False
      # 取消所有后续的自动运行
      self.canvas.after_cancel("automatic_run")

    def run_game(self):
      self.initialize()
      if self.auto:
            self.automatic_run()
      self.mainloop()

    def automatic_run(self):
      if not hasattr(self, "game_over_called"):
            ls = len(self.snake_list)
            if self.snake_list == self.snake_list:
                if self.snake_list > self.snake_list:
                  self.run(0,1)
                else:
                  self.run(0,-1)
            else:
                if self.snake_list > self.snake_list:
                  self.run(1,0)
                else:
                  self.run(-1,0)
      if self.auto:
            self.canvas.after(500,self.automatic_run)

if __name__ == '__main__':
    game = Game()

FishC 发表于 2025-5-8 23:55:17

代码问题分析与修改建议

这个贪吃蛇程序有几个关键问题需要修复,以下是主要修改点:


[*]1. 初始化蛇身错误
原代码:self.snake_list =
修改为:

self.snake_list = [(5, 8)]# 添加初始坐标
self.snake_dir = (1, 0)   # 添加初始移动方向


[*]2. 按键绑定失效
原代码事件字符串为空:
self.bind("", self.move_right)
正确绑定方式:

self.bind("<Right>", self.move_right)
self.bind("<Left>", self.move_left)
self.bind("<Up>", self.move_up)
self.bind("<Down>", self.move_down)


[*]3. 移动逻辑错误
修改移动方法(以move_right为例):

def move_right(self, event):
    if self.snake_dir != (-1, 0):# 禁止反向移动
      self.snake_dir = (1, 0)


[*]4. 自动移动逻辑重构
修改自动移动方法:

def automatic_run(self):
    if self.auto:
      head_x, head_y = self.snake_list
      food_dx = self.food_x - head_x
      food_dy = self.food_y - head_y
      
      # 简单AI自动寻路
      if abs(food_dx) > abs(food_dy):
            self.snake_dir = (1 if food_dx > 0 else -1, 0)
      else:
            self.snake_dir = (0, 1 if food_dy > 0 else -1)
      
      self.run(*self.snake_dir)
      self.after(200, self.automatic_run)



完整修改建议


# 在__init__方法中添加初始化方向
self.snake_dir = (1, 0)# 初始向右移动

# 修改run方法核心逻辑
def run(self, dx, dy):
    new_head = (self.snake_list + dx,
                self.snake_list + dy)
   
    if self.is_dead(*new_head):
      self.game_over()
      return
   
    self.snake_list.insert(0, new_head)
   
    if new_head == (self.food_x, self.food_y):
      self.flip(food=True)
    else:
      self.snake_list.pop()
      self.flip()

# 修改碰撞检测
def is_dead(self, x, y):
    if (x < 0 or y < 0 or
      x >= self.width or y >= self.height or
      (x, y) in self.snake_list):
      return True
    return False


改进建议

[*]添加分数统计功能
[*]实现难度等级(通过调节移动速度)
[*]添加暂停/继续功能(空格键控制)
[*]使用更智能的食物生成算法


这个修改后的版本应该可以正常运行基础贪吃蛇功能,方向键控制移动,自动模式下蛇会追踪食物。建议从基础版本开始逐步添加新功能。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

ydwb 发表于 2025-5-9 07:11:36

还不错的

快速收敛 发表于 2025-5-9 08:32:34

能自己写出来,太强了{:10_254:}

yueyueyue1023W 发表于 2025-5-9 09:57:41

太强了

~风介~ 发表于 2025-5-9 10:40:46

厉害厉害{:5_106:}

不二如是 发表于 2025-5-9 11:40:51

有趣~

某一个“天” 发表于 2025-5-9 22:41:04

{:10_256:}

sfqxx 发表于 2025-5-10 09:20:19

不二如是 发表于 2025-5-9 11:40
有趣~

这个评分的 C 币怎么加的

不二如是 发表于 2025-5-10 09:32:03

sfqxx 发表于 2025-5-10 09:20
这个评分的 C 币怎么加的

发优质内容(帖子、评论),多@我{:10_256:}

sfqxx 发表于 2025-5-10 09:35:54

不二如是 发表于 2025-5-10 09:32
发优质内容(帖子、评论),多@我

{:10_323:}

不二如是 发表于 2025-5-10 09:38:01

sfqxx 发表于 2025-5-10 09:35


{:10_256:}{:10_256:}{:10_256:}之前的好贴链接也可以发我

sfqxx 发表于 2025-5-10 10:13:10

不二如是 发表于 2025-5-10 09:38
之前的好贴链接也可以发我

{:10_323:}
之前的好帖都被您评过了{:10_250:}{:10_275:}

小伤口 发表于 2025-5-11 11:01:16

nice呀,学习了{:7_130:}

阳光开朗大难孩 发表于 2025-5-11 17:09:43

厉害

zxlhbqhxy 发表于 2025-5-12 15:55:22

有时红点会出现在蛇的身上

pyzyd 发表于 2025-5-12 16:50:44

本帖最后由 pyzyd 于 2025-5-12 16:51 编辑

zxlhbqhxy 发表于 2025-5-12 15:55
有时红点会出现在蛇的身上

哈哈,我以前玩的就是这种,只是不会出现在头上

jerry_126 发表于 2025-5-21 15:59:25

{:5_101:}非常好

Mr.江南 发表于 2025-5-21 18:58:59

厉害

player-none 发表于 2025-5-24 11:27:30

加油!
页: [1] 2
查看完整版本: tkinter制作的简易贪吃蛇