Я делаю змею, используя pygame для школьного задания, и она функциональна и работает, но проблема в том, что иногда, когда змея ест пищу, новая еда появляется внутри хвоста змеи. Причина, по которой я не уверен, как это изменить, заключается в том, что способ, которым он генерирует случайное размещение еды, использует случайный диапазон в сетке, и я в любом случае не знаю, как исключить хвост змеи из этого диапазона/регенерировать его, если он появляется внутри там. Это фундаментальная проблема с использованием random.randrange или есть простое решение, сохраняющее большую часть кода. Выделенный код сверху двумя строками ниже
foodX = round(random.randrange(0,display_width-snake_block)/snake_block)*snake_block
foodY = round(random.randrange(0,display_height-snake_block)/snake_block)*snake_block
import pygame
import time
import random
pygame.init()
display_width = 600
display_height = 600
display = pygame.display.set_mode((display_width,display_height))
pygame.display.set_caption("Snake")
pureblue = (0,0,255)
purered = (255,0,0)
puregreen = (0,255,0)
red = (125,25,25)
green = (25,125,25)
white = (255,255,255)
black = (1,1,1)
grey = (20,20,20)
darkgrey = (15,15,15)
clock = pygame.time.Clock()
snake_block = 30
snake_speed = 10
font_style = pygame.font.SysFont(None, 50)
def user_snake(snake_block, snake_List):
for x in snake_List:
pygame.draw.rect(display,green,[x[0],x[1], snake_block, snake_block])
def drawGrid(surf):
blockSize = snake_block
surf.fill(grey)
for x in range(display_width):
for y in range(display_height):
rect = pygame.Rect(x*blockSize, y*blockSize,blockSize, blockSize)
pygame.draw.rect(surf,darkgrey, rect, 1)
grid_surf = pygame.Surface(display.get_size())
drawGrid(grid_surf)
def message(msg, colour):
text = font_style.render(msg, True, colour)
display.blit(text, [0, display_height/4])
def SnakeGameLoop():
game_over = False
game_close = False
X = display_width/2
Y = display_height/2
X_change = 0
Y_change = 0
snake_List = []
Length_of_snake = 1
foodX = round(random.randrange(0,display_width-snake_block)/snake_block)*snake_block
foodY = round(random.randrange(0,display_height-snake_block)/snake_block)*snake_block
while not game_over:
while game_close == True:
message("You Lost! Press Q-Quit or C-Play Again", purered)
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
game_over = True
game_close = False
if event.key == pygame.K_c:
SnakeGameLoop()
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_over = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
X_change = -snake_block
Y_change = 0
elif event.key == pygame.K_RIGHT:
X_change = snake_block
Y_change = 0
elif event.key == pygame.K_UP:
X_change = 0
Y_change = -snake_block
elif event.key == pygame.K_DOWN:
X_change = 0
Y_change = snake_block
if event.key == pygame.K_a:
X_change = -snake_block
Y_change = 0
elif event.key == pygame.K_d:
X_change = snake_block
Y_change = 0
elif event.key == pygame.K_w:
X_change = 0
Y_change = -snake_block
elif event.key == pygame.K_s:
X_change = 0
Y_change = snake_block
if X >= display_width or X < 0 or Y >= display_height or Y < 0:
game_close = True
X += X_change
Y += Y_change
display.blit(grid_surf, (0,0))
pygame.draw.rect(display, red, [foodX, foodY, snake_block, snake_block])
snake_Head = []
snake_Head.append(X)
snake_Head.append(Y)
snake_List.append(snake_Head)
if len(snake_List) > Length_of_snake:
del snake_List[0]
for x in snake_List[:-1]:
if x == snake_Head:
game_close = True
user_snake(snake_block,snake_List)
pygame.display.update()
if X == foodX and Y == foodY:
foodX = round(random.randrange(0, display_width - snake_block) / snake_block) * snake_block
foodY = round(random.randrange(0, display_height - snake_block) / snake_block) * snake_block
Length_of_snake += 1
clock.tick(snake_speed)
pygame.quit()
quit()
SnakeGameLoop()
Есть несколько способов решить эту проблему. Одним из простых способов было бы просто сгенерировать координаты, проверить, не сталкиваются ли они со змеей, и зациклиться, пока этого не происходит. Хотя это просто, это может быть очень неэффективно, когда ваша змея занимает много места на экране, и может потребоваться несколько итераций для размещения каждого нового элемента.
Другим способом было бы генерировать случайные координаты, как вы это делаете, и, если они сталкиваются со змеей, проверять ближайший доступный квадрат вокруг этой случайной точки. Это может быть немного сложнее, но должно быть более эффективным. Может произойти случай, когда ваша змея занимает много сжатого пространства (скажем, вы немного ходили по узким кругам), что также может сделать этот случай немного медленным.
Интересным подходом может быть объединение обоих подходов: сгенерировать случайные координаты, если квадрат занят, проверить ближайший доступный квадрат на максимальном расстоянии n квадратов, и если это не поможет, сгенерировать новые координаты. Однако это может быть излишним.
Спасибо, я понимаю, как я мог реализовать первое, но как вы могли сделать второе. Моей первой мыслью было добавить +1 к значению X/Y, но я не совсем уверен, что это сработает.
Вы также можете взять разницу между набором всех координат и набором всех координат, которые в данный момент занимает змея. Затем выберите координату из этой разницы.