だから私はPython(戦艦、三目並べなど)でいくつかのゲームに取り組んでいて、今週のプロジェクトはSnakeです。基本的なセットアップが進んでいます。ヘビは動いて食べ物を食べることができますが、衝突検出やエッジから外れるようにプログラムしていません。問題は応答時間です。以下のコードを実行すると、ヘビがキーの押下に応答することがわかりますが、プレス後、いくつかのフレームと呼びますが、listen()メソッドがどのように機能するのかよくわかりません。適切に使用していますか?そうでない場合は、どのように使用すればよいですか。遅延を修正するにはどうすればよいですか?Pygameについては知っていますが、a)python 3.4(this one http://)の64ビットバージョンを簡単にインストールできません。 www.lfd.uci.edu/~gohlke/pythonlibs/#pygame インストールは簡単ではありません。whlファイルとは何ですか?)そしてb)とにかく自分自身に挑戦したいと思います。どんな助けでもいただければ幸いです。
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()
タートルコードで_while True:
_(sans break
)を使用するときはいつでも、イベントハンドラーを打ち負かしています。代わりに、ontimer()
イベントを使用して、イベントハンドラーと互換性のあるコードを実行する必要があります。以下は、これを行うためのコードの書き直しと、その他の機能およびスタイルの調整です。
_from turtle import Turtle, Screen
import random
import time
SIZE = 20
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 - SIZE // 2 - 1, self.y - SIZE // 2 - 1)
turtle.begin_fill()
for _ in range(4):
turtle.forward(SIZE - SIZE // 10)
turtle.left(90)
turtle.end_fill()
class Food:
def __init__(self, x, y):
self.x = x
self.y = y
self.is_blinking = True
def changelocation(self):
# I haven't programmed it to spawn outside the snake's body yet
self.x = random.randint(0, SIZE) * SIZE - 200
self.y = random.randint(0, SIZE) * SIZE - 200
def drawself(self, turtle):
# similar to the Square drawself, but blinks on and off
if self.is_blinking:
turtle.goto(self.x - SIZE // 2 - 1, self.y - SIZE // 2 - 1)
turtle.begin_fill()
for _ in range(4):
turtle.forward(SIZE - SIZE // 10)
turtle.left(90)
turtle.end_fill()
def changestate(self):
# controls the blinking
self.is_blinking = not self.is_blinking
class Snake:
def __init__(self):
self.headposition = [SIZE, 0] # keeps track of where it needs to go next
self.body = [Square(-SIZE, 0), Square(0, 0), Square(SIZE, 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] + SIZE * self.nextX, self.headposition[1] + SIZE * 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] + SIZE * self.nextX, self.headposition[1] + SIZE * self.nextY]
else:
self.crashed = True # more unsuccessful collision detection
def moveup(self): # pretty obvious what these do
self.nextX, self.nextY = 0, 1
def moveleft(self):
self.nextX, self.nextY = -1, 0
def moveright(self):
self.nextX, self.nextY = 1, 0
def movedown(self):
self.nextX, self.nextY = 0, -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] + SIZE * self.nextX, self.headposition[1] + SIZE * 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 = Screen()
self.artist = Turtle(visible=False)
self.artist.up()
self.artist.speed("slowest")
self.snake = Snake()
self.food = Food(100, 0)
self.counter = 0 # this will be used later
self.commandpending = False # as will this
self.screen.tracer(0) # follow it so far?
self.screen.listen()
self.screen.onkey(self.snakedown, "Down")
self.screen.onkey(self.snakeup, "Up")
self.screen.onkey(self.snakeleft, "Left")
self.screen.onkey(self.snakeright, "Right")
def nextFrame(self):
self.artist.clear()
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()
if self.counter == 10:
self.food.changestate() # makes the food flash slowly
self.counter = 0
else:
self.counter += 1
self.food.drawself(self.artist) # show the food and snake
self.snake.drawself(self.artist)
self.screen.update()
self.screen.ontimer(lambda: self.nextFrame(), 100)
def snakeup(self):
if not self.commandpending:
self.commandpending = True
self.snake.moveup()
self.commandpending = False
def snakedown(self):
if not self.commandpending:
self.commandpending = True
self.snake.movedown()
self.commandpending = False
def snakeleft(self):
if not self.commandpending:
self.commandpending = True
self.snake.moveleft()
self.commandpending = False
def snakeright(self):
if not self.commandpending:
self.commandpending = True
self.snake.moveright()
self.commandpending = False
game = Game()
screen = Screen()
screen.ontimer(lambda: game.nextFrame(), 100)
screen.mainloop()
_
これはあなたが探している種類の応答を提供しますか?
このようにスピーディーなゲームを作るのはおそらく挑戦です(しかしそれはすべて悪いわけではありません)。 listen()
はonkey()
sの後に続くべきだと思います。
また、重複したコードをすべて取り除くことも検討する必要があります。コピー/貼り付けしてから変更するのは、短期的には簡単に思えるかもしれません。ただし、(フォーラムで質問した後のように)大きな変更を加える必要がある場合は、面倒でエラーが発生しやすくなります。
PS(EDIT)また、Snake.moveOneStep()メソッドは、自己衝突をチェックするためだけにSquareの新しいインスタンスを作成します。これは、優雅さのために贅沢なようです。 python(ho、ho)がチェックスルーできる場所のリストを保持することをお勧めします(これとは別に、おそらく機能しません。print(Square(1,2) in [Square(1,2)])
を試してください)
def check_self_collision(self, x, y):
for s in self.body:
if s.x == x and s.y == y:
return False
return True
def moveOneStep(self):
if self.check_self_collision(self.nextposition[0], self.nextposition[1]):
# attempt (unsuccessful) at collision detection
self.body.append(Square(self.nextposition[0], self.nextposition[1]))