python中,用tkinter模块写贪吃蛇
Posted 缘兮Fate
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python中,用tkinter模块写贪吃蛇相关的知识,希望对你有一定的参考价值。
如果转载标注出处,谢谢!
本作品属于作者原创作品!
下面是一些游戏画面:
游戏说明:
死亡条件:碰壁、吃自己!
状态:只有吃了食物才会随机生成其中一种状态,分别是:稳如老狗、幸运光滑、衰神附体之一
状态:稳如老狗:相对于上一次速度不变!
状态:幸运光滑:相对于上一次速度变慢!
状态:衰神附体:相对于上一次速度边快!
总Buff:总体速率对比刚开始是快还是慢,如果是正直代表慢,如果是负值代表快!
该说的就这么多了!
加油,快来开启你的欧皇人生吧~
本作品是用tkinter模块的canvas画图组件创作的!如果大家有什么好的提议或者说不解之处都可以发帖回复,免费分享自己写的小游戏,也希望能够有相同兴趣爱好的朋友,一起互粉探讨和进步,如果你喜欢我的作品。那么请给我一个关注把,谢谢。
发帖不易,希望大家能给个关注和分享,如果不想发评论也可以发私信给我的哈,我也会时常查看的!关于作品种如果有不解的也欢迎加好友探讨,谢谢你的来访,下面是原创代码部分了,模块基本都是系统自带的。所以不用担心的了!
import tkinter
import time
import random
from threading import Thread, Event
from tkinter import Canvas
from copy import deepcopy
# 游戏数值统计类
class MyScore(object):
str_score = "Score:"
str_buff = \'状态:\'
str_random = \'总Buff:\'
def __init__(self):
self.game_window = Canvas(root, width=width, height=23, bg=\'Snow\') # \'Snow\'
self.game_window.place(x=2, y=2)
self.font_format = (\'宋体\', 12)
self.score = -10
self.buff = 0
self.var_buff = \'稳如老狗\'
self.var_random = 0
self.score_id = None
self.lever_id = None
self.buff_id = None
self.random_id = None
self.sum = 0
# 绘制线框
def show_frame(self):
self.game_window.create_rectangle(2, 2, 301, 24)
self.game_window.create_rectangle(85, 2, 195, 24)
# 增加积分提示
def show_game_score(self):
self.score += 10
self.score_id = self.game_window.create_text(
10, 13, text=MyScore.str_score + str(self.score), font=self.font_format, anchor=tkinter.W)
# 删除积分对象
def del_show_game_score(self):
if self.score_id is not None:
self.game_window.delete(self.score_id)
self.score_id = None
# 随机值显示
def show_game_random(self):
self.sum += self.buff
self.random_id = self.game_window.create_text(
200, 13, text=MyScore.str_random + \'%.2f\' % self.sum, font=self.font_format, anchor=tkinter.W)
# 删除随机值显示
def del_show_game_random(self):
if self.random_id is not None:
self.game_window.delete(self.random_id)
self.random_id = None
# 增加状态显示
def show_game_buff(self):
if self.buff > 0:
self.var_buff = \'幸运光环\'
elif self.buff < 0:
self.var_buff = \'衰神附体\'
else:
self.var_buff = \'稳如老狗\'
self.buff_id = self.game_window.create_text(
141, 13, text=MyScore.str_buff + self.var_buff, font=self.font_format)
# 删除状态显示
def del_show_game_buff(self):
if self.buff_id is not None:
self.game_window.delete(self.buff_id)
self.buff_id = None
# 游戏界面类
class MyCanvas(object):
msg_1 = "游戏说明"
msg_2 = "1.开始\\暂停\\继续:Enter\\空格键"
msg_3 = "2.移动方向:按wasd键"
msg_end = "GAME OVER"
def __init__(self):
self.game_window = Canvas(root, width=width, height=height, bg=\'Tan\') # Tan
self.game_window.place(x=2, y=27)
self.showlist = []
self.font_format = (\'宋体\', 12)
def show_frame(self):
self.game_window.create_rectangle(2, 2, width + 1, height + 1)
my_score.show_frame()
# 绘制说明文本
def game_description(self):
if not len(self.showlist):
id_bg = self.game_window.create_rectangle(20, 70, 280, 200, fill=\'Snow\', width=1)
id_1 = self.game_window.create_text(150, 100, text=MyCanvas.msg_1, font=self.font_format)
id_2 = self.game_window.create_text(26, 135, text=MyCanvas.msg_2, font=self.font_format, anchor=tkinter.W)
id_3 = self.game_window.create_text(26, 170, text=MyCanvas.msg_3, font=self.font_format, anchor=tkinter.W)
self.showlist.extend([id_bg, id_1, id_2, id_3])
# 删除游戏结束,说明文字并清空id!
def del_game_description(self):
[self.game_window.delete(elt) for elt in self.showlist]
self.showlist.clear()
# 游戏结束,说明文字!
def show_game_over(self):
self.game_window.create_text(150, 135, text=MyCanvas.msg_end, font=(\'Arial\', 30), )
# 食物类
class Food(object):
def __init__(self):
self.food = []
self.x = None
self.y = None
self.bg = \'Bisque\'
# 生产食物对象
def produce_food(self):
# 判定食物的坐标不能在蛇身体
while True:
self.x = (random.randint(0, 299) // 10) * 10
self.y = (random.randint(0, 399) // 10) * 10
for snake_x, snake_y in snake.node:
if self.x == snake_x and self.y == snake_y:
break
else:
self.food.append((self.x, self.y))
self.food.append(game_window.create_rectangle(self.x, self.y, self.x + 10, self.y + 10, fill=self.bg))
break
# 判断食物是否为空
def is_empty(self):
if not len(self.food):
return True
# 删除食物对象 清列表
def del_food(self):
if not self.is_empty():
game_window.delete(self.food[-1])
self.food.clear()
# 蛇类
class Snake(object):
def __init__(self):
# 存放节点数据
self.node = []
# 控制事件开关,也即是控制游戏开始\\暂停\\继续
self.e = Event()
# id是存放绘色块的对象
self.id = []
# 定义蛇头的坐标 游戏窗口的正中间 每个蛇块占10像素的等宽高
self.head_x = ((width - 10) // 10 // 2) * 10
self.head_y = ((height - 10) // 10 // 2) * 10
# 蛇尾坐标
self.end_x = None
self.end_y = None
# 蛇的朝向
self.direction = \'up\'
# 蛇的间隔时长
self.t_snake = 0.12
# 结束游戏的标志 真为判定游戏结束
self.is_game_over = False
# 删除所有对象id,node
def del_all_id_node(self):
[game_window.delete(elt) for elt in self.id]
self.node.clear()
# 判断节点是否为空
def is_empty(self):
if not len(self.node):
return True
# 增加头部对象同步至列表id,node 如果节点超过2个就要变色原先头节点
def add_headnode(self):
new_head_id = game_window.create_rectangle(
self.head_x, self.head_y, self.head_x + 10, self.head_y + 10, fill=bg_snake)
self.id.insert(0, new_head_id)
self.node.insert(0, [self.head_x, self.head_y])
# 增加尾部对象同步至列表id,node
def add_endnode(self):
end_id = game_window.create_rectangle(
self.end_x, self.end_y, self.end_x + 10, self.end_y + 10, fill=bg_snake_end)
self.id.append(end_id)
self.node.append([self.end_x, self.end_y])
# 删除尾部对象同步至列表id,node
def del_endnode(self):
end_id = self.id.pop()
game_window.delete(end_id)
self.node.pop()
# 判断是否吃到
def is_eat_food(self):
if self.head_x == food.x and self.head_y == food.y:
# 删除食物对象及id
food.del_food()
# 生成食物
food.produce_food()
return True
# 更新游戏相关参数显示
def update_parameters(self):
# 吃到食物
# 增加更新积分显示
my_score.del_show_game_score()
my_score.show_game_score()
# 游戏状态显示
my_score.buff = random.uniform(-0.1, 0.1)
my_score.del_show_game_buff()
my_score.show_game_buff()
# 更新随机值显示
my_score.del_show_game_random()
my_score.show_game_random()
# 吃到食物后更新速度显示
def update_t_snake(self):
# 当buff跟原先速度相加 如果小于0 则降速至肉眼能看到的死亡
if self.t_snake + my_score.buff <= 0:
self.t_snake = 0.01
else:
self.t_snake += my_score.buff
# 游戏结束
def game_over(self):
# 显示结束文字说明
my_canvas.show_game_over()
# 要清空蛇对象id,node,清空食物对象
self.del_all_id_node()
food.del_food()
# 移动一步的封装
def one_step(self):
# 绘制头节点
self.add_headnode()
# 判断是否吃到自己
if self.is_eat_self():
self.is_game_over = True
# 判断吃到食物,不删除尾结点
if self.is_eat_food():
# 更新游戏相关参数显示
self.update_parameters()
# 更新游戏下次启动速度
self.update_t_snake()
# 节点总计达到2个及以上要开始做第二位节点变色处理
if len(self.node) >= 2:
self.change_colour()
else:
# 未吃到食物且大于等于2节点,变色处理
if len(self.node) >= 2:
self.change_colour()
# 未吃到食物且就一个节点,删除尾节点
self.del_endnode()
# 节点总计达到2个及以上要开始做第二位节点变色处理
def change_colour(self):
# 因为无法直接变色,只能绘制对象后在删除对象 也同步至ID
second_id = game_window.create_rectangle(
self.node[1][0], self.node[1][1], self.node[1][0] + 10, self.node[1][1] + 10, fill=bg_snake_end)
# 删除原对应位置id
game_window.delete(self.id[1])
del self.id[1]
self.id.insert(1, second_id)
# 出场蛇头同步增加id,node
def make_snake_head(self):
if self.is_empty():
head_id = game_window.create_rectangle(
self.head_x, self.head_y, self.head_x + 10, self.head_y + 10, fill=bg_snake)
self.id.append(head_id)
self.node.append([self.head_x, self.head_y])
# 判定是否吃到自己
def is_eat_self(self):
if len(self.node) >= 2:
for snake_x, snake_y in self.node[1:]:
if self.head_x == snake_x and self.head_y == snake_y:
return True
# 游戏开始的时候 加载相关显示菜单
def load_show(self):
# 增加积分显示
my_score.show_game_score()
# 增加状态显示
my_score.show_game_buff()
# 随机值显示
my_score.show_game_random()
# 游戏说明显示
my_canvas.game_description()
# 描边游戏框
my_canvas.show_frame()
# 游戏开始入口
def start(self):
self.load_show()
self.run()
def run(self):
while True:
# 先等待游戏开始
self.e.wait()
# 头节点 用深拷贝防止出现数值问题
self.head_x, self.head_y = deepcopy(self.node[0][0]), deepcopy(self.node[0][1])
# 尾节点
self.end_x, self.end_y = deepcopy(self.node[-1][0]), deepcopy(self.node[-1][1])
# 判断方向
if self.direction == \'up\':
# 越界判定顶部
if self.head_y - 10 in range(0, height):
self.head_y -= 10
self.one_step()
else:
self.is_game_over = True
elif self.direction == \'down\':
# 越界判定底部
if self.head_y + 10 in range(0, height):
self.head_y += 10
self.one_step()
else:
self.is_game_over = True
elif self.direction == \'left\':
# 越界判定左边
if self.head_x - 10 in range(0, width):
self.head_x -= 10
self.one_step()
else:
self.is_game_over = True
else:
# 越界判定右边
if self.head_x + 10 in range(0, width):
self.head_x += 10
self.one_step()
else:
self.is_game_over = True
# 走完判定是否结束游戏
if self.is_game_over:
self.game_over()
break
time.sleep(self.t_snake)
# 按键触发的各类事件 判定移动方向的
def change_direction(self, event):
if event.char.upper() == \'W\':
self.direction = \'up\'
elif event.char.upper() == \'S\':
self.direction = \'down\'
elif event.char.upper() == \'A\':
self.direction = \'left\'
elif event.char.upper() == \'D\':
self.direction = \'right\'
# 开始游戏\\继续\\暂停 Enter\\Spaca键
elif event.char.upper() == \'\\r\' or event.char.upper() == \' \':
# 刚开始游戏 只会运行一次
if len(my_canvas.showlist) != 0:
# 进入这里代表已经开始游戏了,所以删除显示的游戏说明
my_canvas.del_game_description()
# 出场生成食物
food.produce_food()
# 出场蛇头绘制
self.make_snake_head()
# 控制游戏开始\\继续\\暂停开关
if self.e.is_set():
self.e.clear()
else:
self.e.set()
else:
pass
if __name__ == \'__main__\':
# 定义根(游戏)窗口的基本信息 居中显示
root = tkinter.Tk()
root.title(\'My Snake\')
width_root, height_root = 306, 431 # 300 425
width_max, height_max = root.maxsize()
size_center = \'%dx%d+%d+%d\' % (
width_root, height_root, (width_max - width_root) / 2, (height_max - height_root) / 2)
root.geometry(size_center)
root.resizable(width=False, height=False)
# 画布尺寸 还有游戏的相关尺寸
width, height = 300, 400
# 设置蛇颜色参数
bg_snake = \'Indigo\'
bg_snake_end = \'MediumPurple\'
# 初始化画布对象
my_canvas = MyCanvas()
# 获得画布对象
game_window = my_canvas.game_window
# 初始化数值对象
my_score = MyScore()
# 生成蛇类
snake = Snake()
# 生成食物类
food = Food()
# 绑定主窗口事件 主要是为了记录键盘的操作
root.bind(\'<KeyPress>\', snake.change_direction)
# 开始游戏
t1 = Thread(target=snake.start)
t1.setDaemon(True)
t1.start()
# 主窗口循环防止游戏结束
root.mainloop()
如果转载标注出处,谢谢!
以上是关于python中,用tkinter模块写贪吃蛇的主要内容,如果未能解决你的问题,请参考以下文章