Как настроить неравенство для проверки на "потребление" (в основном, столкновение)
Я пытаюсь сделать игру на змею в python с pygame... той, которая движется и ест еду. Но я не могу заставить печенье двигаться, когда "змея" проходит над ним.
Я попытался установить неравенство, чтобы сравнить положение еды и положение змеи, но это не работает...
import pygame, sys, random, time
screenWidth = 500
gameDisplay = pygame.display.set_mode((screenWidth,screenWidth))
#this begins the game
pygame.init()
#This sets a caption
pygame.display.set_caption("Picnic")
#Variables:
snakeFace = pygame.image.load('morrison.png')
x= 50
y= 50
snakewidth = 30
snakeheight = 30
food1width = 40
food1height = 17
food2width = 25
food2height = 26
food3width = 27
food3height = 23
vel = 5
run = True
lastKey = None
food1 = pygame.image.load("thinMint.png")
food2 = pygame.image.load("cookie.png")
food3 = pygame.image.load("triscuit.png")
randFoodX1 = 0
randFoodY1 = 0
randFoodX2 = 0
randFoodY2 = 0
#randFoodX1 = random.randrange(1, 50, 1) * 10
#randFoodY1 = random.randrange(1, 50, 1) * 10
def generateFoodPosition():
randFoodX1 = random.randrange(1, 40, 1) * 10
randFoodY1 = random.randrange(1, 40, 1) * 10
randFoodX2 = random.randrange(1, 40, 1) * 10
randFoodY2 = random.randrange(1, 40, 1) * 10
randFoodX3 = random.randrange(1, 40, 1) * 10
randFoodY3 = random.randrange(1, 40, 1) * 10
if randFoodX1 == randFoodX2 or randFoodY1 == randFoodY2 or
randFoodY2==randFoodY3 or randFoodY1== randFoodY3 or
randFoodX2 == randFoodX3 or randFoodX3 == randFoodX1:
generateFoodPosition()
else:
return [randFoodX1, randFoodY1, randFoodX2,
randFoodY2, randFoodX3, randFoodY3]
foodPositions = generateFoodPosition()
def checkForConsumption():
if ((x + snakewidth) < (foodPositions[0] + food2width + 5
and (x + snakewidth) > (foodPositions[0] + food2width - 5))) or
((y + snakeheight) < (foodPositions[1] + food2height + 5 and (x +
snakeheight) > (foodPositions[1] + food2height - 5))):
foodPositions[0] = random.randrange(1, 40, 1) * 10
foodPositions[1] = random.randrange(1, 40, 1) * 10
if ((x + snakewidth) < (foodPositions[2] + food2width + 5 and (x
+ snakewidth) > (foodPositions[2] + food2width - 5))) or ((y +
snakeheight) < (foodPositions[3] + food2height + 5 and (x +
snakeheight) > (foodPositions[3] + food2height - 5))):
foodPositions[2] = random.randrange(1, 40, 1) * 10
foodPositions[3] = random.randrange(1, 40, 1) * 10
if ((x + snakewidth) < (foodPositions[4] + food2width + 5 and (x +
snakewidth) > (foodPositions[4] + food2width - 5))) or ((y +
snakeheight) < (foodPositions[5] + food2height + 5 and (x +
snakeheight) > (foodPositions[5] + food2height - 5))):
foodPositions[4] = random.randrange(1, 40, 1) * 10
foodPositions[5] = random.randrange(1, 40, 1) * 10
while run:
pygame.time.delay(10) #1/2 milisecond delay
#this controls the "X" button
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
lastKey = event.key
#this controls the movement of the snake
if lastKey == pygame.K_LEFT and x > vel:
x-=vel
if lastKey == pygame.K_RIGHT and x< screenWidth - snakewidth - vel:
x+=vel
if lastKey == pygame.K_DOWN and y < screenWidth - snakeheight - vel:
y+= vel
if lastKey == pygame.K_UP and y > vel:
y-=vel
#if x == (foodPositions[0] or foodPositions[2] or foodPositions[4]) or y== (foodPositions[1] or foodPositions[3] or foodPositions[5]):
checkForConsumption()
gameDisplay.fill((0,0,0))
gameDisplay.blit(snakeFace,(x, y))
gameDisplay.blit(food1, (foodPositions[0], foodPositions[1]))
gameDisplay.blit(food2, (foodPositions[2], foodPositions[3]))
gameDisplay.blit(food3, (foodPositions[4], foodPositions[5]))
pygame.display.update()
print(x)
print(y)
pygame.display.set_mode((screenWidth,screenWidth))
pygame.quit()
Опять же, я ожидал, что когда змея переместится через печенье, чтобы он переместился в другое место
2 ответа
Как уже упоминалось в комментариях, в Pygame есть метод обнаружения столкновений между прямоугольниками. К счастью для вас, метод blit возвращает объект Rect. Это означает, что когда вы рисуете на экране изображение лица змеи и пищи, вы можете удерживать эти возвращаемые значения и использовать их для обнаружения столкновений между змеей и пищей.
Вот короткий фрагмент, чтобы проиллюстрировать, о чем я говорю.
Вы можете изменить код рисования в вашем основном цикле следующим образом:
gameDisplay.fill((0,0,0))
snakeRect = gameDisplay.blit(snakeFace,(x, y))
food1Rect = gameDisplay.blit(food1, (foodPositions[0], foodPositions[1]))
food2Rect = gameDisplay.blit(food2, (foodPositions[2], foodPositions[3]))
food3Rect = gameDisplay.blit(food3, (foodPositions[4], foodPositions[5]))
checkForConsumption() # Note: It is important that you check for consumption after the food and snake have been drawn, as drawing updates their rectangles
pygame.display.update()
Тогда ваш checkForConsumption
метод становится намного проще:
def checkForConsumption():
if snakeRect.coliderect(food1Rect):
# Recalculate the new position of the food just as you did
foodPositions[0] = random.randrange(1, 40, 1) * 10
foodPositions[1] = random.randrange(1, 40, 1) * 10
# Additionally, redraw the food at its new location
gameDisplay.blit(food1, (foodPositions[0], foodPositions[1]))
# Check each of the other pieces of food just as you did the first
Этот метод позволяет вам использовать преимущества методов, встроенных в Pygame, таким образом, вам не нужно теряться в деталях реализации метода обнаружения столкновений, в то же время используя собственные изображения для головы змеи и еды. Хотя можно и не слишком сложно написать свой собственный метод обнаружения столкновений, этот способ намного более чистый и использует инструменты, предоставленные Pygame.
Я сделал это в моем проекте:
def collision_check(enemy_list, player_pos):
for enemy_pos in enemy_list:
if detect_collision(enemy_pos, player_pos):
return True
return False
def detect_collision(player_pos, enemy_pos):
p_x = player_pos[0]
p_y = player_pos[1]
e_x = enemy_pos[0]
e_y = enemy_pos[1]
if (e_x >= p_x and e_x < (p_x + player_size)) or (p_x >= e_x and p_x < (e_x + enemy_size)):
if (e_y >= p_y and e_y < (p_y + player_size)) or (p_y >= e_y and p_y < (e_y + enemy_size)):
return True
return False