Pygame - Найти, какая сторона попала во время столкновения между двумя прямоугольниками

1

Извините за мой английский и начинающие знания Python

Я пытаюсь найти способ, во время столкновения между двумя прямоугольниками (движущаяся пуля и коробка), какая сторона коробки попала в пулю. В настоящее время я использую rect.midtop, midright, midleft, midbottom пули, чтобы найти его. Моя проблема в том, что пуля перемещается на несколько пикселей одновременно, и когда пуля попадает в коробку, но недостаточно близко к центру, она регистрирует неправильное коллизия.

Пример:

Пуля идет из нижней части экрана, и я вижу, что это должно быть коллизия с нижней стороной поля, но оно не касается rect.midtop, а вместо этого затрагивает rect.midright и регистрирует неправильное событие столкновения.,

Вот мой код столкновения:

if self.bullet.rect.collidelist(self.listbox):
            self.bullet.pretx1 = 1
            self.bullet.pretx2 = 1
            self.bullet.prety = 1
            self.bullet.pret = 1
            for box in self.listbox:
                if box.rect.collidepoint(self.bullet.rect.midtop) or box.rect.collidepoint(self.bullet.rect.midbottom) and self.a == 1:
                    self.a = 0
                    print("vertical")
                    print(self.bullet.angle)
                    self.bullet.angle = abs(360 - self.bullet.angle)
                    print(self.bullet.angle)
                    self.listbox.remove(box)
                elif box.rect.collidepoint(self.bullet.rect.midleft) or box.rect.collidepoint(self.bullet.rect.midright) and self.a == 1:
                    self.a = 0
                    print("horizontal")
                    print(self.bullet.angle)
                    self.bullet.angle = 180 - self.bullet.angle
                    print(self.bullet.angle)
                    if self.bullet.angle < 0:
                        self.bullet.angle += 360
                        print(self.bullet.angle)
                    self.listbox.remove(box)

Как бы вы это сделали? Я пытался получить прямую линию, сравнивая углы, используя маски, но я не мог найти решение для работы.

Спасибо за ваше время!

  • 0
    Прямоугольник имеет 8 точек (+ центр), и вы можете проверить все 9 точек: github.com/furas/python-examples/tree/master/pygame/collisions
  • 0
    В некоторых играх используется другой метод: если пуля движется влево, она может столкнуться только с левой стороны. И тогда цель может столкнуться только на нужный размер. То же самое с другими направлениями. С этим предположением вы можете использовать стандартный метод для проверки столкновения, и вам не нужно проверять каждую точку отдельно.
Показать ещё 2 комментария
Теги:
pygame

1 ответ

1

Используйте вектор направления (dx, dy) от центра box к центру bullet, чтобы определить, подходит ли рамка слева, справа, сверху или снизу:

dx = self.bullet.rect.centerx - box.rect.centerx 
dy = self.bullet.rect.centery - box.rect.centery

4 направления, которые должны быть проверены:

dir     = [(-1, 0), (1, 0),  (0, -1), (0, 1)]
dirName = ["left",  "right", "top",   "bottom"]

Вы должны определить то направление, которое близко к (dx, dy). Это можно сделать путем сравнения точечного произведения вектора (dx, dy) и векторов с четырьмя направлениями, что аналогично проверке, существует ли точка в круговом секторе или нет в Python

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

Изображение 174551

dot( A, B ) == | A | * | B | * cos( angle_A_B ) 

Точечное произведение двумерных векторов A и B можно рассчитать с помощью 2 умножений и 1 сложения:

dotAB = Ax * Bx + Ay * By 

Направление шкафа - это направление, при котором получается максимальное произведение точек. Максимальный кулачок можно найти по max:

max_dir = max([i for i in range(len(dir))], key = lambda i: dx*dir[i][0] + dy*dir[i][1])

например

dir     = [(-1, 0), (1, 0),  (0, -1), (0, 1)]
dirName = ["left",  "right", "top",   "bottom"]

for box in self.listbox:

    if box.rect.colliderect(self.bullet.rect):

        dx = self.bullet.rect.centerx - box.rect.centerx 
        dy = self.bullet.rect.centery - box.rect.centery 

        max_dir = max([i for i in range(len(dir))], key = lambda i: dx*dir[i][0] + dy*dir[i][1])
        print("hit", dirName[max_dir]) 

        # [...]

Ещё вопросы

Сообщество Overcoder
Наверх
Меню