在蛇形程序上需要有关用户输入的帮助

时间:2019-12-18 21:34:23

标签: python tkinter input tkinter-canvas

所以,我正在使用tkinter库编写一个蛇程序。该程序在全球范围内都可以使用,但是如果我给两个输入太快的话,我的输入处理确实会有点问题,只有最后一个会被解释。而且我真的不知道如何解决这个问题,我试图在每个玩家输入之后强制进行更新,但这显然不是一个好的解决方案,因为它迫使蛇移动并使其能够传送,所以如果有人有解决这个问题的想法。我确信我的代码可以进行改进,但现在我想重点关注第一个问题。

import tkinter as tk
import numpy.random as rd

class snake:
    def __init__(self,n,m):
        self.n = n
        self.m = m
        self.body = [(n//2,m//2),(n//2,m//2-1)]
        self.lenght = 2
        self.food = (0,0)
        self.relocate_food()
        self.Game = -2
        self.vector = (0,1)  #(0,-1) = up, (0,1) = right, (0,1) = down, (-1,0) = left
        self.speed = 120

    def up(self):
        self.vector = (-1,0)  
    def right(self):
        self.vector = (0,1) 
    def down(self):
        self.vector = (1,0)      
    def left(self):
        self.vector = (0,-1)


    def relocate_food(self):
        x = rd.randint(0,self.n)
        y = rd.randint(0,self.m)
        i = 0
        test = True
        while i<self.lenght and test:
            if (x,y) == self.body[i]:
                test = False
                self.relocate_food()
            else:
                i += 1
        if i == self.lenght:
            self.food = (x,y)


    def collide(self):
        head = self.body[0]
        for i in range(1,self.lenght):
            if head == self.body[i]:
                self.Game = -1
                break
            x,y = head
            if x>=self.n or y>=self.m or x<0 or y<0:
                self.Game = -1

    def eat(self):
        head = self.body[0]
        if head == self.food:           
            self.lenght +=1
            x0, y0 = self.body[-1]
            x1, y1 = self.body[-2]
            x = x0 - x1
            y = y0 - y1
            self.body.append((x0+x,y0+y))
            self.relocate_food()
            if self.lenght%5 == 0:
                self.speed = int(self.speed * 0.90)




    def move(self):
        dx, dy = self.vector     
        last_x, last_y = self.body[0]
        new_x = last_x + dx
        new_y = last_y + dy
        self.body[0] = (new_x, new_y)
        for k in range(1, self.lenght):
            x, y = self.body[k]
            self.body[k] = (last_x,last_y)
            last_x, last_y = x, y
        return 




class screen(snake):
    def __init__(self,root,n,m):
        snake.__init__(self,n,m)
        root.minsize(n*20,m*20)
        root.maxsize(n*20,m*20)
        root.configure(background='white')
        self.root = root
        self.n = n
        self.m = m
        self.speed = 130
        self.canvas = tk.Canvas(root, width = n*20, height =m*20,bg='black')
        self.canvas.bind_all("<Key-Up>",self.move_up)
        self.canvas.bind_all("<Key-Down>",self.move_down)
        self.canvas.bind_all("<Key-Left>",self.move_left)
        self.canvas.bind_all("<Key-Right>",self.move_right)
        self.canvas.grid(row=1,column=0)
        self.draw_snake()
        self.draw_food()


    def draw_snake(self):
        y,x = self.body[0]
        self.canvas.create_rectangle(x*20,y*20,(x+1)*20,(y+1)*20,fill= 'red4')
        for k in range(1,self.lenght):
            y,x = self.body[k]
            self.canvas.create_rectangle(x*20,y*20,(x+1)*20,(y+1)*20,fill= 'red')

    def draw_food(self):
        y,x =self.food
        self.canvas.create_rectangle(x*20,y*20,(x+1)*20,(y+1)*20,fill= 'green')

    def move_up(self,event):
        if self.Game == -2:
            self.Game =0
            self.up()
            self.update()
        else:
            self.up()


    def move_down(self,event):
        if self.Game == -2:
            self.Game =0
            self.down()
            self.update()
        else:
            self.down()

    def move_left(self,event):
        if self.Game == -2:
            self.Game =0
            self.left()
            self.update()
        else:
            self.left()

    def move_right(self,event):
        if self.Game == -2:
            self.Game =0
            self.right()
            self.update()
        else:
            self.right()


    def update(self):
        if self.Game == -2:
            return 
        self.move()
        self.eat()
        self.collide()
        if self.Game == -1:
            self.root.destroy()
            return 
        self.canvas.delete("all")
        self.draw_snake()
        self.draw_food()
        self.root.after(self.speed,self.update)

window = tk.Tk()
snake = screen(window,35,35)
snake.update()
window.mainloop()     

2 个答案:

答案 0 :(得分:1)

这并不是一个错误。动画使用每120毫秒执行一次的“更新”功能。因此,如果您在120毫秒内(即两次连续调用'update'之间)敲击2个箭头键,则仅考虑最后一次敲击,因为每次蛇更新仅考虑一个翻译向量。在这一点上没有人会责怪您,因为时间控制动画是在给定时间范围内的离散过程。这是获得流畅动画和常规动画的唯一解决方案(所有视频游戏都基于这样的过程),因此很明显是正确的。

但是,您的代码可能仍会在几个方面进行改进。例如,在每个动画帧处,删除所有Canvas项目并为蛇元素和食物创建一组全新的项目(“ create_rectangle”)。这不是很有效。最好简单地更改项目的坐标(从doc中检查Canvas.coords函数)。请注意,为蛇设置动画仅需要将先前的尾巴位置移动到新的头部位置,以产生移动中的野兽的错觉。因此,每帧只需要移动1个项目(吃食物时就移动2个项目),这必须更快地处理。

答案 1 :(得分:0)

感谢Furas提供的基本思想是我需要的。经过更正的新代码:

def __init__(self, root,n,m):
"""

    """
    self.input = []

"""


     """
def move_up(self,event):
    if self.Game == -2:
        self.Game =0
        self.up()
        self.update()
    else:
        self.input.append(0)

"""
    Same for all the move
    """


def update(self):
    if self.Game == -2:
        return 
    if len(self.input)>3: #Make sure that the player doesn't stack instruction
        self.pop()
    try:
        input = self.input.pop(0)
    except:
        input = -1
    if input == 0:
        self.up()
    elif input == 1:
        self.right()
    elif input == 2:
        self.down()
    elif input == 3:
        self.left()
    self.move()
    self.eat()
    self.collide()
    if self.Game == -1:
        self.root.destroy()
        return 
    self.canvas.delete("all")
    self.draw_snake()
    self.draw_food()
    self.root.after(self.speed,self.update)