Python TKinter 项目 - 贪吃蛇丨【生长吧!Python】
【摘要】 TKinter 项目 - 贪吃蛇
项目分析:
-
构成:
- 蛇 Snake
- 食物 Food
- 世界 World
-
蛇和食物属于整个世界
class World: self.snake self.food
- 上面代码不太友好
- 我们用另外一个思路来分析
-
我们的分析思路
- 食物是一个独立的事物
- 蛇也可以认为是一个独立的事物
- 世界也是,但世界负责显示
class Food():
'''
功能:
1. 出现在画面的某一个地方
2. 一旦被吃,则增加蛇的分数
'''
def __init__(self, queue):
'''
自动产生一个食物
'''
self.queue = queue
self.new_food()
def new_food():
'''
功能:产生一个食物
产生一个食物的过程就是随机产生一个食物坐标的过程
'''
# 注意横纵坐标产生的范围
x = random.randrange(50, 480, 10)
# 同理产生y坐标
# 需要注意的是,我们的正给游戏屏幕一般不需要把他设置成正方形
self.positon = x,y # position存放食物的位置
# 队列,就是一个不能够随意访问内部元素,只能从头弹出一个元素并只能
#从队尾追加元素的list
# 把一个食物产生的消息放入队列
# 消息的格式,自己定义
# 我的定义是: 消息是一个dict, k代表消息类型,v代表此类型的数据
self.queue.put({"food": self.postion})
class Snake(threading.Thread):
'''
蛇的功能:
1. 蛇能动,由我们的上下左右按键控制
2. 蛇每次动,都需要重新计算蛇头的位置
3. 检测是否游戏完事的功能
'''
def __init__(self, world, queue):
threading.Thread.__init__(self)
self.world = world
self.queue
self.points_earned = 0 #游戏分数
self.food = Food(self.queue)
self.snake_points = [(495, 55), (485,55), (465,55), (455,55)]
self.start()
def run(self):
'''
一旦启用多线程调用此函数
要求蛇一直都在跑
'''
if self.world.is_game_over:
self._delete()
while not self.world.is_gave_over:
self.queue.put({"move": self.snake_points})
time.sleep(0.5) #控制蛇的速度
slef.move()
def move(self):
'''
负责蛇的移动
1. 重新计算蛇头的坐标
2. 当蛇头跟食物相遇,则加分,重新生成食物,通知world,加分
3. 否则, 蛇需要动
'''
new_snake_point = self.cal_new_pos() #重新计算蛇头位置
# 蛇头位置跟食物位置相同
if self.food.postion == new_snake_point:
self.points_earned += 1 #得分加1
self.queue.put({"points_earned": self.points_earned})
self.food.new_food() #就得食物被吃掉,产生新的食物
else:
# 需要注意蛇的信息的保存方式
# 每次移动是删除存放蛇的最前位置,并在后面追加
self.snake_points.pop(0)
# 判断程序是否退出,因为新的蛇可能撞墙
self.check_game_over(new_snake_point)
self.snake_points.append(new_snake_point)
def cal_new_position(self):
'''
计算新的 蛇头的位置
'''
last_x, last_y = self.snake_points[-1]
if self.direction == "Up": #direction负责存储蛇移动的方向
new_snake_point = last_x, last_y - 10 #每次移动的跨度是10像素
elif self.direction == 'Down':
# 需要总共判断上下左右四个方向
return new_snake_point
def key_pressed(self, e):
# keysym是按键名称
self.dierection = e.keysym2
def check_game_over(self, snake_point):
'''
判断的依据是蛇头是否和墙相撞
'''
# 把蛇头的坐标拿出来,跟墙的坐标进行判断
x,y = snake_point[0], snake_point[1]
if not -5 < x < 505 or not -5 < y < 315 or snake_point in self.snake_points:
self.queue.put({'game_over': True})
File "<ipython-input-4-643ab43a69c3>", line 8
def move(self):
^
SyntaxError: unexpected EOF while parsing
clss World(Tk):
'''
用来模拟整个游戏画板
'''
def __init__(self):
Tk.__init__(self)
self.queue
self.is_game_ove = False
# 定义画板
self.canvas = Canvas(self, width=500, height=300, bg='red')
self.pack()
# 画出蛇和食物
self.snake = self.cavas.create_line((0,0), (0,0), fill="black", width=10)
self.food = self.canvas.create_rectangle(0,0,0,0,fill='#FFCC4C', outline='#FFCC4C')
self.points_earned = self.canvas.create_text(450, 20,fill='white', text='SCORE: 0'))
self.queue_handler()
def queue_handler(self):
try:
# 需要不断从消息队列拿到消息,所以使用死循环
while True:
task = self.queue.get(block=False)
if task.get("game_over"):
self.game_over()
if task.get("move"):
points = [ x for point in task['move'] for x in point]
#重新绘制蛇
self.canvas.coords(self.snake, *points)
# 同样道理,还需要处理食物,得分
except queue.Empty: #爆出队列为空异常
if not self.is_game_over:
# after的含义是,在多少毫秒后调用后面的函数
self.canvas.after(100, self.queue_handler)
def game_over(self):
'''
游戏结束,清理现场
'''
self.is_game_over = True
self.canvas.create_text("Game Over")
qb = Button(self, text="Quit", command=self.destroy)
rb = Button(self, text="Again", command=self.__init__)
if __main__ == "__main__":
q = queue.Queue()
world = World(q)
snake = Snake(world, q)
world.bind('<Key-Left>', snake.key_pressed)
# 同样绑定右键,上下键
world.mainloop()
【生长吧!Python】有奖征文火热进行中:https://bbs.huaweicloud.com/blogs/278897
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)