需要有关用户输入的蛇程序帮助
Need help on snake program about user's input
所以,我正在使用 tkinter 库编写一个 snake 程序。该程序在全球范围内运行,但如果我太快地提供两个输入,那么我对输入的处理确实有一点问题,只有最后一个会被解释。而且我真的不知道如何解决这个问题我尝试在每个玩家输入后强制更新但这显然不是好的解决方案因为它迫使蛇移动并使其能够传送所以如果有人我会很高兴有解决这个问题的想法。这是我的代码,我确信它可以改进,但现在我想专注于第一个问题。
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()
感谢 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)
这不是真正的错误。您的动画使用每 120 毫秒执行一次的 'update' 函数。因此,如果您在 120 毫秒内(即两次连续调用 'update' 之间)按下 2 个箭头键,则只考虑最后一次命中,因为每次蛇更新只能考虑一个平移向量。没有人可以在这一点上责怪你,因为时间控制动画是一个具有给定时间的离散过程 window。这是获得流畅和规则动画的唯一解决方案(所有视频游戏都基于这样的过程),所以这显然是正确的。
但是,您的代码在几个方面可能仍需改进。例如,在每个动画帧中,您删除所有 Canvas 项并为蛇元素和食物创建一组全新的项 ('create_rectangle')。这不是很有效。最好简单地更改项目的坐标(检查文档中的 Canvas.coords 函数)。请注意,为蛇设置动画只需要将先前的尾巴位置移动到新的头部位置,以产生移动的野兽的错觉。所以每帧只需要移动 1 个项目(吃东西时 2 个项目),这必须更快地处理。
所以,我正在使用 tkinter 库编写一个 snake 程序。该程序在全球范围内运行,但如果我太快地提供两个输入,那么我对输入的处理确实有一点问题,只有最后一个会被解释。而且我真的不知道如何解决这个问题我尝试在每个玩家输入后强制更新但这显然不是好的解决方案因为它迫使蛇移动并使其能够传送所以如果有人我会很高兴有解决这个问题的想法。这是我的代码,我确信它可以改进,但现在我想专注于第一个问题。
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()
感谢 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)
这不是真正的错误。您的动画使用每 120 毫秒执行一次的 'update' 函数。因此,如果您在 120 毫秒内(即两次连续调用 'update' 之间)按下 2 个箭头键,则只考虑最后一次命中,因为每次蛇更新只能考虑一个平移向量。没有人可以在这一点上责怪你,因为时间控制动画是一个具有给定时间的离散过程 window。这是获得流畅和规则动画的唯一解决方案(所有视频游戏都基于这样的过程),所以这显然是正确的。
但是,您的代码在几个方面可能仍需改进。例如,在每个动画帧中,您删除所有 Canvas 项并为蛇元素和食物创建一组全新的项 ('create_rectangle')。这不是很有效。最好简单地更改项目的坐标(检查文档中的 Canvas.coords 函数)。请注意,为蛇设置动画只需要将先前的尾巴位置移动到新的头部位置,以产生移动的野兽的错觉。所以每帧只需要移动 1 个项目(吃东西时 2 个项目),这必须更快地处理。