鱼C论坛

 找回密码
 立即注册
查看: 13153|回复: 103

[作品展示] tkinter模块写的一个贪吃蛇游戏!附【详细源码】和【注释】回帖有奖前百位

[复制链接]
回帖奖励 32 鱼币 回复本帖可获得 1 鱼币奖励! 每人限 1 次
发表于 2021-9-1 16:40:41 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 gdmao002 于 2021-9-13 12:14 编辑

问个问题 怎么设置回帖可见?
游戏名:贪吃蛇

游戏说明:
死亡条件:碰壁、吃自己!
状态:只有吃了食物才会随机生成其中一种状态,分别是:稳如老狗、幸运光滑、衰神附体之一
状态:稳如老狗:相对于上一次速度不变!
状态:幸运光滑:相对于上一次速度变慢!
状态:衰神附体:相对于上一次速度变快!

总Buff:总体速率对比刚开始是快还是慢,如果是正值代表慢,如果是负值代表快!
该说的就这么多了!
加油,快来开启你的欧皇人生吧~

游戏图片展示:

                               
登录/注册后可看大图


                               
登录/注册后可看大图


                               
登录/注册后可看大图


                               
登录/注册后可看大图


代码部分:
  1. import tkinter
  2. import time
  3. import random
  4. from threading import Thread, Event
  5. from tkinter import Canvas


  6. # 游戏数值统计类
  7. class MyScore(object):
  8.     str_score = "Score:"
  9.     str_buff = '状态:'
  10.     str_random = '总Buff:'

  11.     def __init__(self):
  12.         self.game_window = Canvas(root, width=width, height=23, bg='Snow')  # 'Snow'
  13.         self.game_window.place(x=2, y=2)
  14.         self.font_format = ('宋体', 12)
  15.         self.score = -10
  16.         self.buff = 0
  17.         self.var_random = 0
  18.         self.var_buff = '稳如老狗'
  19.         self.sum = 0

  20.     # 绘制矩形框
  21.     def show_frame(self):
  22.         self.game_window.create_rectangle(2, 2, 301, 24, tag=("frame",))
  23.         self.game_window.create_rectangle(85, 2, 195, 24, tag=("frame",))

  24.     # 增加积分提示
  25.     def show_game_score(self):
  26.         self.score += 10
  27.         self.game_window.create_text(
  28.             10, 13, text=MyScore.str_score + str(self.score), font=self.font_format, anchor=tkinter.W, tag=('score',))

  29.     # 随机值显示
  30.     def show_game_random(self):
  31.         self.sum += self.buff
  32.         self.game_window.create_text(
  33.             200, 13, text=MyScore.str_random + '%.2f' % self.sum, font=self.font_format, anchor=tkinter.W,
  34.             tag=('random',))

  35.     # 增加状态显示
  36.     def show_game_buff(self):
  37.         if self.buff > 0:
  38.             self.var_buff = '幸运光环'
  39.         elif self.buff < 0:
  40.             self.var_buff = '衰神附体'
  41.         else:
  42.             self.var_buff = '稳如老狗'
  43.         self.game_window.create_text(
  44.             141, 13, text=MyScore.str_buff + self.var_buff, font=self.font_format, tag=('buff',))


  45. # 游戏界面类
  46. class MyCanvas(object):
  47.     msg_1 = "游戏说明"
  48.     msg_2 = "1.开始\暂停\继续:Enter\Space"
  49.     msg_3 = "2.移动方向:按wasd键"
  50.     msg_end = "GAME OVER"
  51.     msg_stop = "  Press Enter\Space\nto continue the game"

  52.     def __init__(self):
  53.         self.game_window = Canvas(root, width=width, height=height, bg='Tan')  # Tan
  54.         self.game_window.place(x=2, y=27)
  55.         self.font_format = ('宋体', 12)
  56.         self.flag = True

  57.     # 绘制矩形框
  58.     def show_frame(self):
  59.         self.game_window.create_rectangle(2, 2, width + 1, height + 1)

  60.     # 绘制说明文本
  61.     def game_description(self):
  62.         self.game_window.create_rectangle(20, 70, 280, 200, fill='Snow', width=1, tag=('description',))
  63.         self.game_window.create_text(150, 100, text=MyCanvas.msg_1, font=self.font_format, tag=('description',))
  64.         self.game_window.create_text(
  65.             32, 135, text=MyCanvas.msg_2, font=self.font_format, anchor=tkinter.W, tag=('description',))
  66.         self.game_window.create_text(
  67.             32, 170, text=MyCanvas.msg_3, font=self.font_format, anchor=tkinter.W, tag=('description',))

  68.     # 游戏结束,说明文字!
  69.     def show_game_over(self):
  70.         self.game_window.create_text(150, 135, text=MyCanvas.msg_end, font=('Arial', 30), tag=("game_over",))

  71.     # 游戏暂停,说明文字!
  72.     def show_game_stop(self):
  73.         self.game_window.create_text(
  74.             150, 135, text=MyCanvas.msg_stop, font=('Arial', 22), fill='white', tag=("game_stop",))


  75. # 食物类
  76. class Food(object):
  77.     def __init__(self):
  78.         self.food = []
  79.         self.x = None
  80.         self.y = None
  81.         self.bg = 'Bisque'

  82.     # 生产食物对象
  83.     def produce_food(self):
  84.         # 判定食物的坐标不能在蛇身体
  85.         while True:
  86.             self.x = (random.randint(0, 299) // 10) * 10
  87.             self.y = (random.randint(0, 399) // 10) * 10
  88.             for snake_x, snake_y in snake.node:
  89.                 if self.x == snake_x and self.y == snake_y:
  90.                     break
  91.             else:
  92.                 self.food.append((self.x, self.y))
  93.                 game_window.create_rectangle(self.x, self.y, self.x + 10, self.y + 10, fill=self.bg, tag=("food",))
  94.                 break

  95.     # 判断食物是否为空
  96.     def is_empty(self):
  97.         if not len(self.food):
  98.             return True

  99.     # 删除食物对象 清列表
  100.     def del_food(self):
  101.         if not self.is_empty():
  102.             game_window.delete("food")
  103.             self.food.clear()


  104. # 蛇类
  105. class Snake(object):
  106.     def __init__(self):
  107.         # 存放节点数据
  108.         self.node = []
  109.         # 控制事件开关,也即是控制游戏开始\暂停\继续
  110.         self.e = Event()
  111.         # 定义蛇头的坐标 游戏窗口的正中间 每个蛇块占10像素的等宽高
  112.         self.head_x = ((width - 10) // 10 // 2) * 10
  113.         self.head_y = ((height - 10) // 10 // 2) * 10
  114.         # 蛇的朝向
  115.         self.direction = 'up'
  116.         # 蛇的间隔时长
  117.         self.t_snake = 0.15
  118.         # 结束游戏的标志 真为判定游戏结束
  119.         self.is_game_over = False
  120.         # 尾结点
  121.         self.end_x = None
  122.         self.end_y = None

  123.     # 删除所有对象id,node
  124.     def del_all_id_node(self):
  125.         game_window.delete('snake')
  126.         self.node.clear()

  127.     # 判断节点是否为空
  128.     def is_empty(self):
  129.         if not self.count:
  130.             return True

  131.     # 未吃到食物的情况:绘制头节node,删除尾节点node,移动id
  132.     def headnode(self):
  133.         # 删除尾部节点
  134.         self.node.pop()
  135.         # 更新头节点
  136.         self.node.insert(0, (self.head_x, self.head_y))
  137.         # 获得尾部对象 find_enclosed 判断在矩形内的对象,如果重叠是无法获得,返回的是元组类型的id对象
  138.         end_id = game_window.find_enclosed(self.end_x - 1, self.end_y - 1, self.end_x + 10 + 1, self.end_y + 10 + 1)[0]
  139.         # 画布方法 coords() 可以将id对象改变位置与大小,目前我们用到改变位置 变到头部位置
  140.         game_window.coords(end_id, self.head_x, self.head_y, self.head_x + 10, self.head_y + 10)
  141.         # 变色处理
  142.         game_window.itemconfig(end_id, fill=bg_snake)

  143.     # 增加头部对象同步至列表node,绘制新id
  144.     def add_headnode(self):
  145.         game_window.create_rectangle(
  146.             self.head_x, self.head_y, self.head_x + 10, self.head_y + 10, fill=bg_snake, tag=("snake",))
  147.         # 头部插入新节点
  148.         self.node.insert(0, (self.head_x, self.head_y))

  149.     # 判断吃到食物后[删除食物对象,并生成新食物]
  150.     def is_eat_food(self):
  151.         if self.head_x == food.x and self.head_y == food.y:
  152.             # 删除食物对象及id
  153.             food.del_food()
  154.             # 生成食物
  155.             food.produce_food()
  156.             return True

  157.     # 更新游戏相关参数显示
  158.     def update_parameters(self):
  159.         # 吃到食物
  160.         # 删除原有积分显示
  161.         my_score.game_window.delete('score')
  162.         # 更新积分显示
  163.         my_score.show_game_score()
  164.         # 删除原有游戏状态显示
  165.         my_score.buff = random.uniform(-0.1, 0.1)
  166.         my_score.game_window.delete('buff')
  167.         # 更新现有游戏状态显示
  168.         my_score.show_game_buff()
  169.         # 删除原有数值显示
  170.         my_score.game_window.delete('random')
  171.         # 更新随机值显示
  172.         my_score.show_game_random()

  173.     # 吃到食物后更新速度显示
  174.     def update_t_snake(self):
  175.         # 当buff跟原先速度相加 如果小于0 则降速至肉眼能看到的死亡
  176.         if self.t_snake + my_score.buff <= 0:
  177.             self.t_snake = 0.01
  178.         else:
  179.             self.t_snake += my_score.buff

  180.     # 游戏结束
  181.     def game_over(self):
  182.         # 显示结束文字说明
  183.         my_canvas.show_game_over()
  184.         # 要清空蛇对象id,node,清空食物对象
  185.         self.del_all_id_node()
  186.         food.del_food()

  187.     # 移动一步的封装
  188.     def one_step(self):
  189.         # 判断是否吃到自己
  190.         if self.is_eat_self():
  191.             self.is_game_over = True
  192.         # 判断吃到食物,不删除尾结点
  193.         if self.is_eat_food():
  194.             # 绘制添加头节点
  195.             self.add_headnode()
  196.             # 更新游戏相关参数显示
  197.             self.update_parameters()
  198.             # 更新游戏下次启动速度
  199.             self.update_t_snake()
  200.         else:
  201.             # 未吃到食物的情况
  202.             # 绘制头节点node,删除尾节点node,移动id,
  203.             self.headnode()
  204.         # 节点总计达到2个及以上要开始做第二位节点变色处理
  205.         if self.count >= 2:
  206.             self.change_colour()

  207.     # 节点总计达到2个及以上要开始做第个蛇身位节点变色处理
  208.     def change_colour(self):
  209.         # 获取第二个位置的对象
  210.         second_id = game_window.find_enclosed(
  211.             self.node[1][0] - 1, self.node[1][1] - 1, self.node[1][0] + 10 + 1, self.node[1][1] + 10 + 1)[0]
  212.         # 画布方法 itemconfig() 能够处理尾部id对象的颜色更替
  213.         game_window.itemconfig(second_id, fill=bg_snake_end)

  214.     # 出场蛇头增加node
  215.     def make_snake_head(self):
  216.         game_window.create_rectangle(
  217.             self.head_x, self.head_y, self.head_x + 10, self.head_y + 10, fill=bg_snake, tag=('snake',))
  218.         self.node.append((self.head_x, self.head_y))

  219.     # 获取节点个数
  220.     @property
  221.     def count(self):
  222.         return len(self.node)

  223.     # 判定是否吃到自己
  224.     def is_eat_self(self):
  225.         if self.count >= 2:
  226.             for snake_x, snake_y in self.node[1:]:
  227.                 if self.head_x == snake_x and self.head_y == snake_y:
  228.                     return True

  229.     # 游戏开始的时候 加载相关显示菜单
  230.     def load_show(self):
  231.         # 增加积分显示
  232.         my_score.show_game_score()
  233.         # 增加状态显示
  234.         my_score.show_game_buff()
  235.         # 随机值显示
  236.         my_score.show_game_random()
  237.         # 游戏说明显示
  238.         my_canvas.game_description()
  239.         # 描边游戏框
  240.         my_canvas.show_frame()
  241.         my_score.show_frame()

  242.     # 游戏开始入口
  243.     def start(self):
  244.         while True:
  245.             self.load_show()
  246.             self.run()
  247.             break

  248.     def run(self):
  249.         while True:
  250.             # 先等待游戏开始
  251.             self.e.wait()
  252.             # 头节点
  253.             self.head_x, self.head_y = self.node[0][0], self.node[0][1]
  254.             # 尾节点
  255.             self.end_x, self.end_y = self.node[-1][0], self.node[-1][1]
  256.             # 判断方向
  257.             if self.direction == 'up':
  258.                 # 越界判定顶部
  259.                 if self.head_y - 10 in range(0, height):
  260.                     self.head_y -= 10
  261.                     self.one_step()
  262.                 else:
  263.                     self.is_game_over = True
  264.             elif self.direction == 'down':
  265.                 # 越界判定底部
  266.                 if self.head_y + 10 in range(0, height):
  267.                     self.head_y += 10
  268.                     self.one_step()
  269.                 else:
  270.                     self.is_game_over = True
  271.             elif self.direction == 'left':
  272.                 # 越界判定左边
  273.                 if self.head_x - 10 in range(0, width):
  274.                     self.head_x -= 10
  275.                     self.one_step()
  276.                 else:
  277.                     self.is_game_over = True
  278.             else:
  279.                 # 越界判定右边
  280.                 if self.head_x + 10 in range(0, width):
  281.                     self.head_x += 10
  282.                     self.one_step()
  283.                 else:
  284.                     self.is_game_over = True
  285.             # 走完判定是否结束游戏
  286.             if self.is_game_over:
  287.                 self.game_over()
  288.                 break
  289.             time.sleep(self.t_snake)

  290.     # 按键触发的各类事件 判定移动方向的
  291.     def change_direction(self, event):
  292.         if event.char.upper() == 'W':
  293.             self.direction = 'up'
  294.         elif event.char.upper() == 'S':
  295.             self.direction = 'down'
  296.         elif event.char.upper() == 'A':
  297.             self.direction = 'left'
  298.         elif event.char.upper() == 'D':
  299.             self.direction = 'right'
  300.         # 开始游戏\继续\暂停 Enter\Spaca键
  301.         elif event.char.upper() == '\r' or event.char.upper() == ' ':
  302.             # 刚开始游戏 只会运行一次
  303.             if my_canvas.flag:
  304.                 # 进入这里代表已经开始游戏了,所以删除显示的游戏说明
  305.                 game_window.delete("description")
  306.                 # 出场生成食物
  307.                 food.produce_food()
  308.                 # 出场蛇头绘制
  309.                 self.make_snake_head()
  310.                 my_canvas.flag = False
  311.             # 控制游戏开始\继续\暂停开关
  312.             if self.e.is_set():
  313.                 # 显示游戏暂停信息
  314.                 my_canvas.show_game_stop()
  315.                 self.e.clear()
  316.             else:
  317.                 # 删除游戏暂停信息
  318.                 game_window.delete("game_stop")
  319.                 self.e.set()

  320.         else:
  321.             pass


  322. if __name__ == '__main__':
  323.     # 定义根(游戏)窗口的基本信息 居中显示
  324.     root = tkinter.Tk()
  325.     root.title('My Snake')
  326.     width_root, height_root = 306, 431  # 300 425
  327.     width_max, height_max = root.maxsize()
  328.     size_center = '%dx%d+%d+%d' % (
  329.         width_root, height_root, (width_max - width_root) / 2, (height_max - height_root) / 2)
  330.     root.geometry(size_center)
  331.     root.resizable(width=False, height=False)

  332.     # 画布尺寸 还有游戏的相关尺寸
  333.     width, height = 300, 400

  334.     # # 设置蛇颜色参数
  335.     bg_snake = 'Indigo'
  336.     bg_snake_end = 'MediumPurple'

  337.     # 初始化画布对象
  338.     my_canvas = MyCanvas()

  339.     # 获得画布对象
  340.     game_window = my_canvas.game_window

  341.     # 初始化数值对象
  342.     my_score = MyScore()

  343.     # 生成蛇类
  344.     snake = Snake()

  345.     # 生成食物类
  346.     food = Food()

  347.     # 绑定主窗口事件 主要是为了记录键盘的操作
  348.     root.bind('<KeyPress>', snake.change_direction)

  349.     # 开始游戏
  350.     t1 = Thread(target=snake.start)
  351.     t1.setDaemon(True)
  352.     t1.start()

  353.     # 主窗口循环
  354.     root.mainloop()
复制代码

评分

参与人数 3荣誉 +15 鱼币 +15 贡献 +6 收起 理由
太阳总会升起 + 5 + 5 + 3
hrpzcf + 5 + 5 + 3 鱼C有你更精彩^_^
小伤口 + 5 + 5

查看全部评分

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2021-9-1 16:43:48 | 显示全部楼层

回帖奖励 +1 鱼币

沙发?玩一下试试
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-9-1 16:52:57 | 显示全部楼层
niuniuniu666 发表于 2021-9-1 16:43
沙发?玩一下试试

好的加油哈~
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-9-1 17:24:26 From FishC Mobile | 显示全部楼层

回帖奖励 +1 鱼币

厉害呀,我也要玩
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-9-1 18:31:36 | 显示全部楼层
小伤口 发表于 2021-9-1 17:24
厉害呀,我也要玩


感谢支持
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-9-1 19:29:32 | 显示全部楼层

回帖奖励 +1 鱼币

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2021-9-1 19:37:35 From FishC Mobile | 显示全部楼层

回帖奖励 +1 鱼币

论坛大神越来越多了
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-9-1 21:42:38 | 显示全部楼层
hrpzcf 发表于 2021-9-1 19:37
论坛大神越来越多了

谢谢支持哈,我还不是大神,论坛大神大有人在的
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-9-2 01:16:08 | 显示全部楼层

回帖奖励 +1 鱼币

大佬嘿嘿
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-9-2 02:27:51 | 显示全部楼层

回帖奖励 +1 鱼币

楼主千金散尽还复来
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-9-2 06:55:59 | 显示全部楼层

回帖奖励 +1 鱼币

挣鱼币做作业
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-9-2 08:44:09 | 显示全部楼层

回帖奖励 +1 鱼币

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2021-9-2 09:07:54 | 显示全部楼层

回帖奖励 +1 鱼币

向大神学习
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-9-2 14:31:31 | 显示全部楼层

回帖奖励 +1 鱼币

一个小小的贪吃蛇要这么多代码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-9-2 15:34:56 | 显示全部楼层

回帖奖励 +1 鱼币

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2021-9-2 16:57:05 | 显示全部楼层
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-9-2 16:58:15 | 显示全部楼层
遇见Tom 发表于 2021-9-2 14:31
一个小小的贪吃蛇要这么多代码

如果只是简单的没有额外的东西是可以少一些代码,而且你看我代码基本都有注释,所以整体看很多,其实也没多少的
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-9-2 17:29:02 | 显示全部楼层

没有,我只是为了水鱼币,这个表情是表情里面的第一个,我都没看是啥,直接就点啦,没想到是个生气的表情,尴尬啦!
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-9-2 19:15:01 | 显示全部楼层
番杰 发表于 2021-9-2 17:29
没有,我只是为了水鱼币,这个表情是表情里面的第一个,我都没看是啥,直接就点啦,没想到是个生气的表情 ...

哈哈了解了解
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-9-2 21:53:46 | 显示全部楼层

回帖奖励 +1 鱼币

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-4-27 04:58

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表