Коллизии тайловой карты Pygame (вернуть, какая сторона сталкивается) - PullRequest
0 голосов
/ 16 июня 2020

У меня есть уровень, сделанный из спрайтов (в группе спрайтов), эти спрайты помещены в двухмерный массив, это тайловая карта.

У меня есть спрайт игрока (в другой группе спрайтов)

Как сделать из этого 2d платформер? Мне просто нужен фрагмент кода, который может сказать, с какой стороны игрок касается плитки, и вернуть ее, чтобы я мог затем создать условия, которые остановят его движение из стороны в сторону или остановят его прыжок. Я пробовал много разных вещей и просто не могу заставить это работать правильно из-за тайловой карты.

1 Ответ

1 голос
/ 17 июня 2020

Я здесь, чтобы ответить на вопросы людей, которые хотят научиться программированию. Если вопрос, очевидно, звучит как «дай мне код» или «Я скопировал какой-то код отсюда и здесь; теперь исправь это для меня!», Я не вкладываю много усилий в ответ. Итак, я надеюсь, вы понимаете, почему приведенный ниже ответ является в основном теоретическим и не содержит проверенного и отлаженного кода.

Я полагаю, вы говорите о 2D-игре с «гравитацией», когда игрок прыгает и как-то падает. Если вы говорите о 2D подобном румянцу (вид сверху вниз, без гравитации), некоторые из приведенных ниже обозначений могут быть немного неточными, но logi c то же самое.

Основанная на тайлах «карта» или «уровень» может рассматриваться как набор слоев. Я бы разделил спрайты с возможностью столкновения в отдельную группу спрайтов, назовем их platforms. Декоративные плитки могут быть go в группу background. Фон - это нижний слой, который, помимо необходимости рисования, в противном случае можно игнорировать. Одно фоновое изображение может быть лучше для этого, чем целая куча спрайтов.

Итак, всякий раз, когда игрок пытается двигаться, платформы необходимо проверять на столкновение с новым thoretical-location before движение завершено. В объекте PyGame Sprite есть удобная функция под названием pygame.sprite.spritecollideany(). Это позволяет вашему коду довольно легко проверять наличие столкновений между одним спрайтом и группой спрайтов while:

collided_with = player_sprite.spritecollideany( platform_sprite_group )
if ( collided_with != None ):
    print( "Player collided with sprite: " + str( collided_with ) )

Еще одна удобная функция - pygame.sprite.groupcollide(), это отлично подходит для столкновения группы спрайтов с другой - например куча стрел против кучи врагов. Но вы также можете создать группу спрайтов с одним элементом и использовать его также на отдельных объектах.

На самом деле вам не нужно знать, с какой стороны игрока сталкивается с платформами. Это неявная информация, потому что вы уже знаете, в какую сторону движется игрок. Основа тестирования столкновений заключается в том, что понимание того, что перемещение спрайта более чем на 1 пиксель за раз, может перемещать игрока поверх существующего спрайта, даже не касаясь стороны. Скажем, игрок двигался очень быстро, его следующая позиция для движения может быть прямо в середине другого спрайта! Так в какую сторону он попал? (Сторона, с которой переместился игрок.)

Так, например: если игрок хотел переместиться на 10 пикселей влево, но край платформы находится на расстоянии 5 пикселей, игрок «сталкивается», но не касается. Как только происходит столкновение, код должен определить, каким было бы допустимое движение, и скорректировать движение в соответствии с этой дельтой. Поскольку объекты-спрайты PyGame основаны на объекте Rect , это достаточно простой тест с использованием Rect x, y и width, height. 'X' и 'y' представляют верхний левый угол, поэтому нам нужно учитывать ширину спрайтов:

# Player has tried to move delta_x and delta_y pixels
collided_with = player_sprite.spritecollideany( background_sprite_group )
if ( collided_with != None ):
    print( "Player collided with sprite: " + str( collided_with ) )
    if ( delta_x > 0 ):    # moving right
        # collides on right side
        distance_to_sprite_x = player_sprite.rect.x + player_sprite.rect.width - collided_with.rect.x
    elif ( delta_x < 0 ):  # moving left
        # collides on left side (take width of sprite into account)
        distance_to_sprite_x = player_sprite.rect.x - collided_with.rect.x + collided_with.rect.width
    else:                  # not moving horizontally
        distance_to_sprite_x = 0
    # Adjust the x-movement to make it rest against the sprite
    delta_x = distance_to_sprite_x

    # TODO: similarly for delta_y 

Очевидно, что игрок движется достаточно быстро (много пикселей на frame) теоретически он мог «перепрыгнуть» всю платформу, а не столкнуться, пройдя сквозь нее. Приведенный выше код страдает этой скрытой ошибкой. Но большинству игр не нужно беспокоиться о подобной ситуации.

Так что я надеюсь, что logi c, представленного выше, достаточно, чтобы вы начали обрабатывать всевозможные коллизии. Просто попробуйте заставить код работать, это лучший способ научиться. Напишите что-нибудь, проверьте это, сделайте ошибки, задайте вопросы по этому поводу. Мы готовы помочь. Легко попасть в ловушку, просто скопировав и вставив чужой код (который иногда бывает среднего качества), чтобы получить это «быстрое решение». Но на самом деле это не поможет вам изучить основы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...