我的问题很难解释所以请运行代码看看是什么 继续
我正在尝试调整蛇游戏的代码,以便蛇不会与屏幕边界发生碰撞。我正在使用可在此处找到的现有代码code on stackexchange。我正在使用Gareth Rees的修订版本(参见他答案的底部)。
我添加了无边界选项(全局布尔WORLD_BOUNDARIES = False
),但我有问题要正确,因为我不习惯pythons语法。
我改编的代码看起来像这样。更改/添加的代码位于snake类更新函数内的'''****...'''
注释之间。下面的代码可以安全地执行,但有一些与无边界相关的错误。我确实尝试在向下方向修复错误,但它没有工作,所以我评论了它。
from collections import deque
from itertools import *
import pygame
from random import randrange
import sys
from pygame.locals import *
class Vector(tuple):
"""A tuple that supports some vector operations.
>>> v, w = Vector((1, 2)), Vector((3, 4))
>>> v + w, w - v, v * 10, 100 * v, -v
((4, 6), (2, 2), (10, 20), (100, 200), (-1, -2))
"""
def __add__(self, other): return Vector(v + w for v, w in zip(self, other))
def __radd__(self, other): return Vector(w + v for v, w in zip(self, other))
def __sub__(self, other): return Vector(v - w for v, w in zip(self, other))
def __rsub__(self, other): return Vector(w - v for v, w in zip(self, other))
def __mul__(self, s): return Vector(v * s for v in self)
def __rmul__(self, s): return Vector(v * s for v in self)
def __neg__(self): return -1 * self
FPS = 60 # Game frames per second
SEGMENT_SCORE = 50 # Score per segment
SNAKE_SPEED_INITIAL = 4.0 # Initial snake speed (squares per second)
SNAKE_SPEED_INCREMENT = 0.25 # Snake speeds up this much each time it grows
SNAKE_START_LENGTH = 4 # Initial snake length in segments
WORLD_SIZE = Vector((20, 20)) # World size, in blocks
BLOCK_SIZE = 24 # Block size, in pixels
WORLD_BOUNDARIES = False
BACKGROUND_COLOR = 45, 45, 45
SNAKE_COLOR = 0, 255, 0
FOOD_COLOR = 255, 0, 0
DEATH_COLOR = 255, 0, 0
TEXT_COLOR = 255, 255, 255
DIRECTION_UP = Vector(( 0, -1))
DIRECTION_DOWN = Vector(( 0, 1))
DIRECTION_LEFT = Vector((-1, 0))
DIRECTION_RIGHT = Vector(( 1, 0))
DIRECTION_DR = DIRECTION_DOWN + DIRECTION_RIGHT
# Map from PyGame key event to the corresponding direction.
KEY_DIRECTION = {
K_w: DIRECTION_UP, K_UP: DIRECTION_UP,
K_s: DIRECTION_DOWN, K_DOWN: DIRECTION_DOWN,
K_a: DIRECTION_LEFT, K_LEFT: DIRECTION_LEFT,
K_d: DIRECTION_RIGHT, K_RIGHT: DIRECTION_RIGHT,
}
class Snake(object):
def __init__(self, start, start_length):
self.speed = SNAKE_SPEED_INITIAL # Speed in squares per second.
self.timer = 1.0 / self.speed # Time remaining to next movement.
self.growth_pending = 0 # Number of segments still to grow.
self.direction = DIRECTION_UP # Current movement direction.
self.segments = deque([start - self.direction * i
for i in xrange(start_length)])
def __iter__(self):
return iter(self.segments)
def __len__(self):
return len(self.segments)
def change_direction(self, direction):
"""Update the direction of the snake."""
# Moving in the opposite direction of current movement is not allowed.
if self.direction != -direction:
self.direction = direction
def head(self):
"""Return the position of the snake's head."""
return self.segments[0]
def tail(self):
"""Return the tail of the snake."""
return deque(islice(self.segments, 1, None))
def update(self, dt, direction):
"""Update the snake by dt seconds and possibly set direction."""
self.timer -= dt
if self.timer > 0:
# Nothing to do yet.
return
# Moving in the opposite direction of current movement is not allowed.
if self.direction != -direction:
self.direction = direction
self.timer += 1 / self.speed
'''************************************************************************************
***************************************************************************************
***************************************************************************************'''
if not WORLD_BOUNDARIES:
head = self.head()
if self.direction == DIRECTION_DOWN and head[1] == WORLD_SIZE[1]-1:
self.segments[0]=Vector((head[0], 0))
# new_head = (head[0], 0)
# new_tail = deque([x+self.direction for x in self.tail()])
# self.segments = new_tail.extendleft([new_head])
# print new_head
# print new_tail
if self.direction == DIRECTION_UP and head[1] == 0:
self.segments[0]=Vector((head[0], WORLD_SIZE[1]-1))
if self.direction == DIRECTION_RIGHT and head[0] == WORLD_SIZE[0]-1:
self.segments[0]=Vector((0, head[1]))
if self.direction == DIRECTION_LEFT and head[0] == 0:
self.segments[0]=Vector((WORLD_SIZE[0]-1, head[1]))
'''************************************************************************************
***************************************************************************************
***************************************************************************************'''
# Add a new head.
self.segments.appendleft(self.head() + self.direction)
if self.growth_pending > 0:
self.growth_pending -= 1
else:
# Remove tail.
self.segments.pop()
def grow(self):
"""Grow snake by one segment and speed up."""
self.growth_pending += 1
self.speed += SNAKE_SPEED_INCREMENT
def self_intersecting(self):
"""Is the snake currently self-intersecting?"""
it = iter(self)
head = next(it)
return head in it
class SnakeGame(object):
def __init__(self):
pygame.display.set_caption('PyGame Snake')
self.block_size = BLOCK_SIZE
self.window = pygame.display.set_mode(WORLD_SIZE * self.block_size)
self.screen = pygame.display.get_surface()
self.clock = pygame.time.Clock()
self.font = pygame.font.Font('freesansbold.ttf', 20)
self.world = Rect((0, 0), WORLD_SIZE)
self.reset()
def reset(self):
"""Start a new game."""
self.playing = True
self.next_direction = DIRECTION_UP
self.score = 0
self.snake = Snake(self.world.center, SNAKE_START_LENGTH)
self.food = set()
self.add_food()
def add_food(self):
"""Ensure that there is at least one piece of food.
(And, with small probability, more than one.)
"""
while not (self.food and randrange(4)):
food = Vector(map(randrange, self.world.bottomright))
if food not in self.food and food not in self.snake:
self.food.add(food)
def input(self, e):
"""Process keyboard event e."""
if e.key in KEY_DIRECTION:
self.next_direction = KEY_DIRECTION[e.key]
elif e.key == K_SPACE and not self.playing:
self.reset()
def update(self, dt):
"""Update the game by dt seconds."""
self.snake.update(dt, self.next_direction)
# If snake hits a food block, then consume the food, add new
# food and grow the snake.
head = self.snake.head()
if head in self.food:
self.food.remove(head)
self.add_food()
self.snake.grow()
self.score += len(self.snake) * SEGMENT_SCORE
# If snake collides with self or the screen boundaries, then
# it's game over.
if self.snake.self_intersecting() or not self.world.collidepoint(self.snake.head()):
self.playing = False
def block(self, p):
"""Return the screen rectangle corresponding to the position p."""
return Rect(p * self.block_size, DIRECTION_DR * self.block_size)
def draw_text(self, text, p):
"""Draw text at position p."""
self.screen.blit(self.font.render(text, 1, TEXT_COLOR), p)
def draw(self):
"""Draw game (while playing)."""
self.screen.fill(BACKGROUND_COLOR)
for p in self.snake:
pygame.draw.rect(self.screen, SNAKE_COLOR, self.block(p))
for f in self.food:
pygame.draw.rect(self.screen, FOOD_COLOR, self.block(f))
self.draw_text("Score: {}".format(self.score), (20, 20))
def draw_death(self):
"""Draw game (after game over)."""
self.screen.fill(DEATH_COLOR)
self.draw_text("Game over! Press Space to start a new game", (20, 150))
self.draw_text("Your score is: {}".format(self.score), (140, 180))
def play(self):
"""Play game until the QUIT event is received."""
while True:
dt = self.clock.tick(FPS) / 1000.0 # convert to seconds
for e in pygame.event.get():
if e.type == QUIT:
return
elif e.type == KEYUP:
self.input(e)
if self.playing:
self.update(dt)
self.draw()
else:
self.draw_death()
pygame.display.flip()
if __name__ == '__main__':
pygame.init()
SnakeGame().play()
pygame.quit()
答案 0 :(得分:3)
from collections import deque
from itertools import *
import pygame
from random import randrange
import sys
from pygame.locals import *
class Vector(tuple):
"""A tuple that supports some vector operations.
>>> v, w = Vector((1, 2)), Vector((3, 4))
>>> v + w, w - v, v * 10, 100 * v, -v
((4, 6), (2, 2), (10, 20), (100, 200), (-1, -2))
"""
def __add__(self, other): return Vector(v + w for v, w in zip(self, other))
def __radd__(self, other): return Vector(w + v for v, w in zip(self, other))
def __sub__(self, other): return Vector(v - w for v, w in zip(self, other))
def __rsub__(self, other): return Vector(w - v for v, w in zip(self, other))
def __mul__(self, s): return Vector(v * s for v in self)
def __rmul__(self, s): return Vector(v * s for v in self)
def __neg__(self): return -1 * self
FPS = 60 # Game frames per second
SEGMENT_SCORE = 50 # Score per segment
SNAKE_SPEED_INITIAL = 4.0 # Initial snake speed (squares per second)
SNAKE_SPEED_INCREMENT = 0.25 # Snake speeds up this much each time it grows
SNAKE_START_LENGTH = 4 # Initial snake length in segments
WORLD_SIZE = Vector((20, 20)) # World size, in blocks
BLOCK_SIZE = 24 # Block size, in pixels
WORLD_BOUNDARIES = False
BACKGROUND_COLOR = 45, 45, 45
SNAKE_COLOR = 0, 255, 0
FOOD_COLOR = 255, 0, 0
DEATH_COLOR = 255, 0, 0
TEXT_COLOR = 255, 255, 255
DIRECTION_UP = Vector(( 0, -1))
DIRECTION_DOWN = Vector(( 0, 1))
DIRECTION_LEFT = Vector((-1, 0))
DIRECTION_RIGHT = Vector(( 1, 0))
DIRECTION_DR = DIRECTION_DOWN + DIRECTION_RIGHT
# Map from PyGame key event to the corresponding direction.
KEY_DIRECTION = {
K_w: DIRECTION_UP, K_UP: DIRECTION_UP,
K_s: DIRECTION_DOWN, K_DOWN: DIRECTION_DOWN,
K_a: DIRECTION_LEFT, K_LEFT: DIRECTION_LEFT,
K_d: DIRECTION_RIGHT, K_RIGHT: DIRECTION_RIGHT,
}
class Snake(object):
def __init__(self, start, start_length):
self.speed = SNAKE_SPEED_INITIAL # Speed in squares per second.
self.timer = 1.0 / self.speed # Time remaining to next movement.
self.growth_pending = 0 # Number of segments still to grow.
self.direction = DIRECTION_UP # Current movement direction.
self.segments = deque([start - self.direction * i
for i in xrange(start_length)])
def __iter__(self):
return iter(self.segments)
def __len__(self):
return len(self.segments)
def change_direction(self, direction):
"""Update the direction of the snake."""
# Moving in the opposite direction of current movement is not allowed.
if self.direction != -direction:
self.direction = direction
def head(self):
"""Return the position of the snake's head."""
return self.segments[0]
def tail(self):
"""Return the tail of the snake."""
return deque(islice(self.segments, 1, None))
def update(self, dt, direction):
"""Update the snake by dt seconds and possibly set direction."""
self.timer -= dt
if self.timer > 0:
# Nothing to do yet.
return
# Moving in the opposite direction of current movement is not allowed.
if self.direction != -direction:
self.direction = direction
self.timer += 1 / self.speed
'''************************************************************************************
***************************************************************************************
***************************************************************************************'''
# Add a new head.
if not WORLD_BOUNDARIES:
head = self.head()
if self.direction == DIRECTION_DOWN and head[1] == WORLD_SIZE[1]-1:
self.segments.appendleft(Vector((head[0], 0)))
elif self.direction == DIRECTION_UP and head[1] == 0:
self.segments.appendleft(Vector((head[0], WORLD_SIZE[1]-1)))
elif self.direction == DIRECTION_RIGHT and head[0] == WORLD_SIZE[0]-1:
self.segments.appendleft(Vector((0, head[1])))
elif self.direction == DIRECTION_LEFT and head[0] == 0:
self.segments.appendleft(Vector((WORLD_SIZE[0]-1, head[1])))
else: self.segments.appendleft(self.head() + self.direction)
else: self.segments.appendleft(self.head() + self.direction)
'''************************************************************************************
***************************************************************************************
***************************************************************************************'''
if self.growth_pending > 0:
self.growth_pending -= 1
else:
# Remove tail.
self.segments.pop()
def grow(self):
"""Grow snake by one segment and speed up."""
self.growth_pending += 1
self.speed += SNAKE_SPEED_INCREMENT
def self_intersecting(self):
"""Is the snake currently self-intersecting?"""
it = iter(self)
head = next(it)
return head in it
class SnakeGame(object):
def __init__(self):
pygame.display.set_caption('PyGame Snake')
self.block_size = BLOCK_SIZE
self.window = pygame.display.set_mode(WORLD_SIZE * self.block_size)
self.screen = pygame.display.get_surface()
self.clock = pygame.time.Clock()
self.font = pygame.font.Font('freesansbold.ttf', 20)
self.world = Rect((0, 0), WORLD_SIZE)
self.reset()
def reset(self):
"""Start a new game."""
self.playing = True
self.next_direction = DIRECTION_UP
self.score = 0
self.snake = Snake(self.world.center, SNAKE_START_LENGTH)
self.food = set()
self.add_food()
def add_food(self):
"""Ensure that there is at least one piece of food.
(And, with small probability, more than one.)
"""
while not (self.food and randrange(4)):
food = Vector(map(randrange, self.world.bottomright))
if food not in self.food and food not in self.snake:
self.food.add(food)
def input(self, e):
"""Process keyboard event e."""
if e.key in KEY_DIRECTION:
self.next_direction = KEY_DIRECTION[e.key]
elif e.key == K_SPACE and not self.playing:
self.reset()
def update(self, dt):
"""Update the game by dt seconds."""
self.snake.update(dt, self.next_direction)
# If snake hits a food block, then consume the food, add new
# food and grow the snake.
head = self.snake.head()
if head in self.food:
self.food.remove(head)
self.add_food()
self.snake.grow()
self.score += len(self.snake) * SEGMENT_SCORE
# If snake collides with self or the screen boundaries, then
# it's game over.
if self.snake.self_intersecting() or not self.world.collidepoint(self.snake.head()):
self.playing = False
def block(self, p):
"""Return the screen rectangle corresponding to the position p."""
return Rect(p * self.block_size, DIRECTION_DR * self.block_size)
def draw_text(self, text, p):
"""Draw text at position p."""
self.screen.blit(self.font.render(text, 1, TEXT_COLOR), p)
def draw(self):
"""Draw game (while playing)."""
self.screen.fill(BACKGROUND_COLOR)
for p in self.snake:
pygame.draw.rect(self.screen, SNAKE_COLOR, self.block(p))
for f in self.food:
pygame.draw.rect(self.screen, FOOD_COLOR, self.block(f))
self.draw_text("Score: {}".format(self.score), (20, 20))
def draw_death(self):
"""Draw game (after game over)."""
self.screen.fill(DEATH_COLOR)
self.draw_text("Game over! Press Space to start a new game", (20, 150))
self.draw_text("Your score is: {}".format(self.score), (140, 180))
def play(self):
"""Play game until the QUIT event is received."""
while True:
dt = self.clock.tick(FPS) / 1000.0 # convert to seconds
for e in pygame.event.get():
if e.type == QUIT:
return
elif e.type == KEYUP:
self.input(e)
if self.playing:
self.update(dt)
self.draw()
else:
self.draw_death()
pygame.display.flip()
if __name__ == '__main__':
pygame.init()
SnakeGame().play()
pygame.quit()