обнаружение столкновения прямоугольников pygame не работает

#python #pygame #collision-detection

#python #pygame #обнаружение столкновения

Вопрос:

Я пытаюсь добавить платформу в свою игру, чтобы после того, как вы нажмете на нее, игрок оставался на платформе, пока она не упадет, и в этом случае она упала бы на землю. Переход работает, но столкновения нет

Я попытался добавить некоторые из приведенных ниже типичных типов детекторов столкновений, но все они имеют недостатки

 class Platform:
    def __init__(self, x, y, background):
        self.xpos = x
        self.ypos = y
        self.picture = background
        self.picture = pygame.transform.scale(self.picture, (500, 100))
        self.rect = self.picture.get_rect()

    def draw(self):
        screen.blit(self.picture, (self.xpos, self.ypos))

class Player:
    def __init__(self, x, y, pic_one, pic_two, pic_three, pic_four):
        self.xpos = x
        self.ypos = y
        self.speed_y = 0
        self.speed_x = 0
        self.picture = pic_one
        self.picture_one = pic_one
        self.picture_two = pic_two
        self.picture_three = pic_three
        self.picture_four = pic_four
        self.on_ground = True
        self.picture = pygame.transform.scale(self.picture, (100, 100))
        self.rect = self.picture.get_rect()

    def update(self):
        self.xpos  = self.speed_x
        self.ypos  = self.speed_y

        GRAVITY = 0.9

        self.speed_y  = GRAVITY  # Accelerate downwards.
        self.xpos  = self.speed_x 
        self.ypos  = self.speed_y


        if self.ypos >= 620:
            self.ypos = 620
            self.speed_y = 0
            self.on_ground = True


        if self.on_ground == True:
            self.speed_y = 0


    def jump(self):
        if self.on_ground:
            self.on_ground = False
            self.speed_y = -20#Makes you move upwards

    def draw(self):
        screen.blit(self.picture, (self.xpos, self.ypos))

    def is_collided_with(self, sprite):
        return self.rect.colliderect(sprite.rect)

player_one = Player(30, 600, player_one_first_pic)
wood_platform = Platform(400, 400, platform_pic)
while True:
    [...]
  

это типичный тип столкновения, который я бы попытался использовать, но, похоже, оператор if никогда не выполняется

 if player_one.rect.bottom == wood_platform.rect.top:
    player_one.on_ground = True
  

другой, на котором я пробовал, который определяет, сталкиваются ли прямоугольники
и оператор if является истинным, даже если прямоугольники не сталкиваются

 if player_one.is_collided_with(wood_platform):
     player_one.on_ground = True 
  

этот метод мне неудобен, потому что его недостаточно

 if player_one.ypos == 600:
    player_one.on_ground = True
  

Фактические результаты для метода, который я использовал, заключались в том, что проигрыватель вообще не сталкивался с деревянной платформой

(Вот диаграмма, если вам нужно немного больше понимания:) player_platform Проверяет наличие столкновения, но, похоже, не работает

 if player_one.rect.y == wood_platform.rect.y:
        print(True)
        player_one.on_ground = True
        on_platform = True

    else:
        on_platform = False
  

изменения после каждого обновления

 self.rect.x = self.xpos
self.rect.y = self.ypos
  

Ответ №1:

Что касается меня, проблема в том, что вы используете self.xpos , self.ypos для перемещения объекта и не меняете значения в self.rect ( self.rect.x , self.rect.y ), но вы используете self.rect для проверки столкновения.

Вы должны установить

 self.rect.x = self.xpos
self.rect.y = self.ypos 
  

прежде чем проверять столкновение.

И вы должны сделать это для всех движущихся объектов. Может быть, лучше делать это после каждого хода.


Вы могли бы использовать только self.rect.x , self.rect.y (вместо self.xpos, self.ypos ), но он может сохранять только целочисленные значения. Вы используете значение с плавающей точкой в gravity и self.rect.x , self.rect.y округляете позицию в меньшую сторону и получаете не очень плавную анимацию.

Но объекты, которые не используют силу тяжести с плавающей точкой или скорость с плавающей точкой, могут использовать только self.rect для сохранения положения.

Комментарии:

1. Итак, если я сейчас сделаю, если player_one.rect.y (игрок один является объектом) == wood_platform.rect. будет ли это работать, потому что это то, что я чувствую себя наиболее комфортно

2. вы можете это сделать, но это может не сработать, если вы перемещаете игрока более чем на один пиксель за каждый ход. В один момент player_one.rect.y может быть меньше, чем wood_platform.rect.y (поэтому оно не сталкивается), а в следующий момент оно может быть больше, чем wood_platform.rect.y (поэтому оно сталкивается) и == не будет его перехватывать. Лучше использовать self.rect.colliderect(other.rect) . Он также может распознавать столкновение слева / справа или когда вы прыгаете и голова игрока касается платформы внизу — поэтому он должен прекратить движение вверх и начать движение вниз.

3. Хорошо, я добавил приведенный выше блок кода, но, похоже, этого все еще не происходит

4. используете ли вы self.rect.x , self.rect.y в плеере и на платформе?

5. Да, я могу подтвердить, что я делаю

Ответ №2:

У меня часто возникает такая же проблема в моей работе. Проверка равенства чисел может завершиться ошибкой при использовании чисел с плавающей точкой. Вы могли бы попытаться изменить это

 if player_one.rect.bottom == wood_platform.rect.top:
    player_one.on_ground = True
  

к этому:

 margin = 0.001 # Whatever amount you feel comfy with.
if wood_platform.rect.top*(1-margin) <= player_one.rect.bottom <= wood_platform.rect.top*(1 margin):
    player_one.on_ground = True