前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >TKinter 项目 - 贪吃蛇

TKinter 项目 - 贪吃蛇

原创
作者头像
ruochen
修改2021-07-22 14:20:12
5880
修改2021-07-22 14:20:12
举报

项目分析:

  • 构成:
    • 蛇 Snake
    • 食物 Food
    • 世界 World
  • 蛇和食物属于整个世界
代码语言:txt
复制
    class World:
代码语言:txt
复制
        self.snake
代码语言:txt
复制
        self.food
代码语言:txt
复制
- 上面代码不太友好
- 我们用另外一个思路来分析
  • 我们的分析思路
    • 食物是一个独立的事物
    • 蛇也可以认为是一个独立的事物
    • 世界也是,但世界负责显示
代码语言:txt
复制
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})
代码语言:txt
复制
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})
代码语言:txt
复制
  File "<ipython-input-4-643ab43a69c3>", line 8
代码语言:txt
复制
    def move(self):
代码语言:txt
复制
                   ^
代码语言:txt
复制
SyntaxError: unexpected EOF while parsing
代码语言:txt
复制
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()
                
                
                
                
                
                
                
                

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 项目分析:
相关产品与服务
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档