一般来说,你必须区分两种不同类型的蛇.在第一种情况下,蛇在一个网格中移动,蛇每移动一次,它就会在网格中向前迈出一个领域。在另一种类型中,蛇的位置不在光栅中,也没有捕捉到网格的区域,位置是自由的,蛇在区域中顺利滑动。
在前者中,身体的每个元素都被捕捉到网格的区域,就像头部一样。另一个更诡异,因为身体元素的位置取决于元素的大小和蛇头的动态、先前位置。
首先是蛇, 捕捉到网格。
蛇的元素可以存储在元组列表中。每个元组包含网格中 snakes 元素的列和行。列表中项目的变化直接跟随蛇的移动。如果蛇移动,则将新位置添加到列表的头部并删除列表的尾部。
例如,我们有一条具有以下元素的蛇:
body = [(3, 3), (3, 4), (4, 4), (5, 4), (6, 4)]
当蛇头从(3, 3)移动到(3, 2)时,新的头部位置被添加到列表的头部(body.insert(0, (3, 2)):
body = [(3, 2), (3, 3), (3, 4), (4, 4), (5, 4), (6, 4)]
最后去掉了ist的尾巴(del body[-1]):
body = [(3, 2), (3, 3), (3, 4), (4, 4), (5, 4)]
最小的例子: repl.it/@Rabbid76/PyGame-SnakeMoveInGrid
import pygame
import random
pygame.init()
COLUMNS, ROWS, SIZE = 10, 10, 20
screen = pygame.display.set_mode((COLUMNS*SIZE, ROWS*SIZE))
clock = pygame.time.Clock()
background = pygame.Surface((COLUMNS*SIZE, ROWS*SIZE))
background.fill((255, 255, 255))
for i in range(1, COLUMNS):
pygame.draw.line(background, (128, 128, 128), (i*SIZE-1, 0), (i*SIZE-1, ROWS*SIZE), 2)
for i in range(1, ROWS):
pygame.draw.line(background, (128, 128, 128), (0, i*SIZE-1), (COLUMNS*SIZE, i*SIZE-1), 2)
def random_pos(body):
while True:
pos = random.randrange(COLUMNS), random.randrange(ROWS)
if pos not in body:
break
return pos
length = 1
body = [(COLUMNS//2, ROWS//2)]
dir = (1, 0)
food = random_pos(body)
run = True
while run:
clock.tick(5)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT: dir = (-1, 0)
elif event.key == pygame.K_RIGHT: dir = (1, 0)
elif event.key == pygame.K_UP: dir = (0, -1)
elif event.key == pygame.K_DOWN: dir = (0, 1)
body.insert(0, body[0][:])
body[0] = (body[0][0] + dir[0]) % COLUMNS, (body[0][1] + dir[1]) % ROWS
if body[0] == food:
food = random_pos(body)
length += 1
while len(body) > length:
del body[-1]
screen.blit(background, (0, 0))
pygame.draw.rect(screen, (255, 0, 255), (food[0]*SIZE, food[1]*SIZE, SIZE, SIZE))
for i, pos in enumerate(body):
color = (255, 0, 0) if i==0 else (0, 192, 0) if (i%2)==0 else (255, 128, 0)
pygame.draw.rect(screen, color, (pos[0]*SIZE, pos[1]*SIZE, SIZE, SIZE))
pygame.display.flip()
现在蛇完全自由定位。
我们必须在列表中跟踪蛇头访问过的所有位置。我们必须将蛇体的元素像链中的珍珠一样放置在列表中的位置上。
关键是计算链中主体的最后一个元素与轨道上后续位置之间的Euclidean distance。
当找到一个距离足够大的新点时,就会将一个新的珍珠(元素)添加到链(主体)中。
dx, dy = body[-1][0]-pos[0], body[-1][1]-pos[1]
if math.sqrt(dx*dx + dy*dy) >= distance:
body.append(pos)
以下函数有 3 个参数。 track 是头部位置列表。 no_pearls 是 shakes 主体的元素数,distance 是元素之间的 Euclidean distance。该函数创建并返回蛇身体位置的列表。
def create_body(track, no_pearls, distance):
body = [(track[0])]
track_i = 1
for i in range(1, no_pearls):
while track_i < len(track):
pos = track[track_i]
track_i += 1
dx, dy = body[-1][0]-pos[0], body[-1][1]-pos[1]
if math.sqrt(dx*dx + dy*dy) >= distance:
body.append(pos)
break
while len(body) < no_pearls:
body.append(track[-1])
del track[track_i:]
return body
最小的例子: repl.it/@Rabbid76/PyGame-SnakeMoveFree
import pygame
import random
import math
pygame.init()
COLUMNS, ROWS, SIZE = 10, 10, 20
WIDTH, HEIGHT = COLUMNS*SIZE, ROWS*SIZE
screen = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
background = pygame.Surface((WIDTH, HEIGHT))
background.fill((255, 255, 255))
for i in range(1, COLUMNS):
pygame.draw.line(background, (128, 128, 128), (i*SIZE-1, 0), (i*SIZE-1, ROWS*SIZE), 2)
for i in range(1, ROWS):
pygame.draw.line(background, (128, 128, 128), (0, i*SIZE-1), (COLUMNS*SIZE, i*SIZE-1), 2)
def hit(pos_a, pos_b, distance):
dx, dy = pos_a[0]-pos_b[0], pos_a[1]-pos_b[1]
return math.sqrt(dx*dx + dy*dy) < distance
def random_pos(body):
pos = None
while True:
pos = random.randint(SIZE//2, WIDTH-SIZE//2), random.randint(SIZE//2, HEIGHT-SIZE//2)
if not any([hit(pos, bpos, 20) for bpos in body]):
break
return pos
def create_body(track, no_pearls, distance):
body = [(track[0])]
track_i = 1
for i in range(1, no_pearls):
while track_i < len(track):
pos = track[track_i]
track_i += 1
dx, dy = body[-1][0]-pos[0], body[-1][1]-pos[1]
if math.sqrt(dx*dx + dy*dy) >= distance:
body.append(pos)
break
while len(body) < no_pearls:
body.append(track[-1])
del track[track_i:]
return body
length = 1
track = [(WIDTH//2, HEIGHT//2)]
dir = (1, 0)
food = random_pos(track)
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT: dir = (-1, 0)
elif event.key == pygame.K_RIGHT: dir = (1, 0)
elif event.key == pygame.K_UP: dir = (0, -1)
elif event.key == pygame.K_DOWN: dir = (0, 1)
track.insert(0, track[0][:])
track[0] = (track[0][0] + dir[0]) % WIDTH, (track[0][1] + dir[1]) % HEIGHT
body = create_body(track, length, 20)
if hit(body[0], food, 20):
food = random_pos(body)
length += 1
screen.blit(background, (0, 0))
pygame.draw.circle(screen, (255, 0, 255), food, SIZE//2)
for i, pos in enumerate(body):
color = (255, 0, 0) if i==0 else (0, 192, 0) if (i%2)==0 else (255, 128, 0)
pygame.draw.circle(screen, color, pos, SIZE//2)
pygame.display.flip()