所以我一直在用Python开发一些游戏(战舰,tic tac toe等),本周的项目是Snake。我已经有了一个基本的设置;蛇可以移动并吃掉食物,但我还没有编程碰撞检测或离开边缘。问题是响应时间。如果你运行下面的代码,你会看到蛇会对按键做出响应,但不会对按键后的几次(我称之为帧)做出响应。我不太明白listen()方法是如何工作的;我是否正确地使用了它?如果没有,我应该如何使用它,如果是,我如何修复延迟?我知道Pygame,但是a)我找不到一个易于安装的python 3.4 64位版本(这个http://www.lfd.uci.edu/~gohlke/pythonlibs/#pygame不容易安装,whl文件到底是什么?)我无论如何都想挑战自己。 任何帮助都将不胜感激。
import random
import turtle
import time
class Square:
def __init__(self, x, y):
self.x = x
self.y = y
def drawself(self, turtle):
# draw a black box at its coordinates, leaving a small gap between cubes
turtle.goto(self.x - 9, self.y - 9)
turtle.begin_fill()
for i in range(4):
turtle.forward(18)
turtle.left(90)
turtle.end_fill()
class Food:
def __init__(self, x, y):
self.x = x
self.y = y
self.state = "ON"
def changelocation(self):
# I haven't programmed it to spawn outside the snake's body yet
self.x = random.randint(0, 20)*20 - 200
self.y = random.randint(0, 20)*20 - 200
def drawself(self, turtle):
# similar to the Square drawself, but blinks on and off
if self.state == "ON":
turtle.goto(self.x - 9, self.y - 9)
turtle.begin_fill()
for i in range(4):
turtle.forward(18)
turtle.left(90)
turtle.end_fill()
def changestate(self):
# controls the blinking
self.state = "OFF" if self.state == "ON" else "ON"
class Snake:
def __init__(self):
self.headposition = [20, 0] # keeps track of where it needs to go next
self.body = [Square(-20, 0), Square(0, 0), Square(20, 0)] # body is a list of squares
self.nextX = 1 # tells the snake which way it's going next
self.nextY = 0
self.crashed = False # I'll use this when I get around to collision detection
self.nextposition = [self.headposition[0] + 20*self.nextX,
self.headposition[1] + 20*self.nextY]
# prepares the next location to add to the snake
def moveOneStep(self):
if Square(self.nextposition[0], self.nextposition[1]) not in self.body:
# attempt (unsuccessful) at collision detection
self.body.append(Square(self.nextposition[0], self.nextposition[1]))
# moves the snake head to the next spot, deleting the tail
del self.body[0]
self.headposition[0], self.headposition[1] = self.body[-1].x, self.body[-1].y
# resets the head and nextposition
self.nextposition = [self.headposition[0] + 20*self.nextX,
self.headposition[1] + 20*self.nextY]
else:
self.crashed = True # more unsuccessful collision detection
def moveup(self): # pretty obvious what these do
self.nextX = 0
self.nextY = 1
def moveleft(self):
self.nextX = -1
self.nextY = 0
def moveright(self):
self.nextX = 1
self.nextY = 0
def movedown(self):
self.nextX = 0
self.nextY = -1
def eatFood(self):
# adds the next spot without deleting the tail, extending the snake by 1
self.body.append(Square(self.nextposition[0], self.nextposition[1]))
self.headposition[0], self.headposition[1] = self.body[-1].x, self.body[-1].y
self.nextposition = [self.headposition[0] + 20*self.nextX,
self.headposition[1] + 20*self.nextY]
def drawself(self, turtle): # draws the whole snake when called
for segment in self.body:
segment.drawself(turtle)
class Game:
def __init__(self):
# game object has a screen, a turtle, a basic snake and a food
self.screen = turtle.Screen()
self.artist = turtle.Turtle()
self.artist.up()
self.artist.hideturtle()
self.snake = Snake()
self.food = Food(100, 0)
self.counter = 0 # this will be used later
self.commandpending = False # as will this
def nextFrame(self):
while True: # now here's where it gets fiddly...
game.screen.listen()
game.screen.onkey(game.snakedown, "Down")
game.screen.onkey(game.snakeup, "Up")
game.screen.onkey(game.snakeleft, "Left")
game.screen.onkey(game.snakeright, "Right")
turtle.tracer(0) # follow it so far?
self.artist.clear()
if self.counter == 5:
# only moves to next frame every 5 loops, this was an attempt to get rid of the turning delay
if (self.snake.nextposition[0], self.snake.nextposition[1]) == (self.food.x, self.food.y):
self.snake.eatFood()
self.food.changelocation()
else:
self.snake.moveOneStep()
self.counter = 0
else:
self.counter += 1
self.food.changestate() # makes the food flash
self.food.drawself(self.artist) # show the food and snake
self.snake.drawself(self.artist)
turtle.update()
self.commandpending = False
time.sleep(0.05)
def snakeup(self):
print("going up") # put this in for debugging purposes
if not self.commandpending:
# should allow only one turn each frame; I don't think it's working
self.snake.moveup()
self.commandpending = True
def snakedown(self):
print("going down")
if not self.commandpending:
self.snake.movedown()
self.commandpending = True
def snakeleft(self):
print("going left")
if not self.commandpending:
self.snake.moveleft()
self.commandpending = True
def snakeright(self):
print("going right")
if not self.commandpending:
self.snake.moveright()
self.commandpending = True
game = Game()
game.nextFrame()
print("game over!")
game.screen.mainloop()
用这种方式快速完成比赛可能是一个挑战(但这并不全是坏事)。我认为之后
listen()
应该在^{您还应该考虑消除所有重复的代码。从短期来看,复制/粘贴然后修改似乎很容易。但是如果你必须做一些重大的改变(比如在论坛上询问之后),那将是乏味的,而且容易出错。
PS(EDIT)还有你的Snake.moveOneStep()方法创建了一个新的Square实例,只是为了检查自碰撞,为了优雅起见,这看起来太奢侈了。最好保留一个python(ho,ho)可以检查的位置列表。(除此之外,可能不起作用。尝试
print(Square(1,2) in [Square(1,2)])
)我的版本:
每当你在turtle代码中使用
while True:
(sansbreak
)时,你就是在击败事件处理程序。相反,您应该使用ontimer()
事件来与事件处理程序兼容地运行代码。下面是我对您的代码进行的重写,以实现这一点以及其他一些功能和样式调整:这是否提供了您正在寻找的响应类型?
相关问题 更多 >
编程相关推荐