Как мне создать обнаружение столкновения для моих прыгающих мячей?

Я закодировал анимацию (на питоне) для трех пляжных мячей, которые подпрыгивают по экрану. Теперь я хочу, чтобы они все столкнулись и могли отскакивать друг от друга. Я был бы очень признателен за любую помощь, которая может быть предложена.

import pygame
import random
import sys
class Ball:


    def __init__(self,X,Y):

        self.velocity = [1,1]
        self.ball_image = pygame.image.load ('Beachball.jpg'). convert()
        self.ball_boundary = self.ball_image.get_rect (center=(X,Y))
        self.sound = pygame.mixer.Sound ('Thump.wav')
        self.rect = self.ball_image.get_rect (center=(X,Y))

if __name__ =='__main__':

    width = 800
    height = 600
    background_colour = 0,0,0
    pygame.init()
    window = pygame.display.set_mode((width, height))
    pygame.display.set_caption("Bouncing Ball animation")
    num_balls = 3
    ball_list = []
    for number in range(num_balls):
        ball_list.append( Ball(random.randint(10, (width - 10)),random.randint(10, (height - 10))) )
    while True:
        for event in pygame.event.get():
                print event 
                if event.type == pygame.QUIT:
                        sys.exit(0)
        window.fill (background_colour)

        for ball in ball_list:
                if ball.ball_boundary.left < 0 or ball.ball_boundary.right > width:
                        ball.sound.play()
                        ball.velocity[0] = -1 * ball.velocity[0]
                if ball.ball_boundary.top < 0 or ball.ball_boundary.bottom > height:
                        ball.sound.play()
                        ball.velocity[1] = -1 * ball.velocity[1]

                ball.ball_boundary = ball.ball_boundary.move (ball.velocity)
                window.blit (ball.ball_image, ball.ball_boundary)
        pygame.display.flip()

person Community    schedule 23.04.2009    source источник
comment
Некоторое время назад я задал аналогичный вопрос: Обнаружение и обработка столкновений мяча с мячом. Там тоже есть хорошие отзывы.   -  person mmcdole    schedule 23.04.2009
comment
возможный дубликат столкновения мяча с мячом - обнаружение и обработка   -  person sarnold    schedule 23.02.2012


Ответы (7)


Обнаружение столкновений для произвольных форм обычно довольно сложно, поскольку вам нужно выяснить, сталкивается ли какой-либо пиксель.

На самом деле это проще с кругами. Если у вас есть две окружности радиуса r1 и r2, столкновение произошло, если расстояние между центрами меньше, чем r1 + r2.

Расстояние между двумя центрами (x1, y1) и (x2, y2) можно рассчитать и сравнить как:

d = sqrt((y2-y1) * (y2-y1) + (x2-x1) * (x2-x1));
if (d < r1 + r2) { ... bang ... }

Или, как указывает jfclavette, квадратные корни дороги, поэтому может быть лучше вычислить, используя простые операции:

dsqrd = (y2-y1) * (y2-y1) + (x2-x1) * (x2-x1);
if (dsqrd < (r1+r2)*(r1+r2)) { ... bang ... }

Сложность заключается в вычислении новых векторов движения (скорости, с которой (x, y) изменяется с течением времени для данного объекта), поскольку вам необходимо учитывать текущие векторы движения и точку контакта.

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

Затем задайте другой вопрос - лучше, чтобы отдельные вопросы были конкретными, чтобы ответы могли быть целенаправленными.

person paxdiablo    schedule 23.04.2009
comment
Просто примечание: получение квадратного корня - довольно дорогостоящая операция, и вы можете возвести в квадрат обе части уравнения, поскольку они обе положительны. Это дает вам d ^ 2 = (y2-y1) * (y2-y1) + (x2-x1) * (x2-x1) и (d ^ 2 ‹(r1 + r2) ^ 2) в качестве теста. - person jfclavette; 23.04.2009
comment
Хороший момент, @jfclavette, особенно если вы хотите, чтобы в ответ было включено максимальное количество кадров в секунду. - person paxdiablo; 23.04.2009

Обнаружение столкновения - это только первый шаг. Давайте разберемся с этим.

Самый быстрый способ сделать это - вычислить их квадратные ограничивающие рамки и посмотреть, не сталкиваются ли они. Две стороны должны пересекаться (верхняя часть 1 и нижняя или 2, и левая часть 1 и правая часть 2, или наоборот), чтобы ограничивающие прямоугольники перекрывали друг друга. Ни перекрытий, ни столкновений.

Теперь, когда они действительно перекрываются, вам нужно рассчитать расстояние между ними. Если это расстояние больше суммы радиусов шаров, то столкновения нет.

Хорошо! Два шара сталкиваются. Теперь что? Что ж, они должны отскакивать друг от друга. То, как они отскакивают, зависит от нескольких факторов.

Во-первых, их эластичность. Два резиновых мяча, отскакивающих друг от друга, отскакивают иначе, чем два стеклянных шара.

Вторая - их начальная скорость. Инерция утверждает, что они захотят продолжать двигаться в том же направлении, в котором начали.

Третий - это масса шаров. Мяч с меньшей массой отскочит от гораздо большей массы с большей скоростью.

Давайте сначала разберемся со вторым и третьим факторами, поскольку они взаимосвязаны.

Два шара редко попадут точно в цель. Гораздо более вероятны скользящие удары. В любом случае удар будет происходить по нормали к касательной, где сталкиваются шары. Вам необходимо вычислить векторную составляющую обоих вдоль этой нормали с учетом их начальных скоростей. Это приведет к паре нормальных скоростей, которые оба шара приведут к столкновению. Сложите сумму и храните где-нибудь под рукой.

Теперь нам нужно выяснить, что отнимет у себя каждый мяч. Результирующая нормальная скорость каждого шара обратно пропорциональна данной массе шара. Другими словами, возьмите величину, обратную массе каждого шара, сложите обе массы вместе, а затем разделите результирующую нормальную скорость от столкновения на основе отношения массы шара к сумме обратной величины масс обоих мячей. Затем добавьте к этому тангенциальную скорость, и вы получите результирующую скорость мяча.

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

person Ignacio Vazquez-Abrams    schedule 23.04.2009
comment
Столкновение круга / круга проще, чем ограничивающая рамка, выровненная по оси, с ограничительной рамкой, выровненной по оси. Просто пропустите часть ограничивающих рамок :) - person jfclavette; 23.04.2009
comment
@jfclavette: я думаю, что он использовал ограничивающие прямоугольники как более простую для расчета первую проверку на потенциальное столкновение перед вычислением расстояний. - person gnovice; 23.04.2009
comment
@gnovice: Да, я это понял. Но Sphere / Sphere или Circle / Circle быстрее, чем Box / Box. Первую проверку на самом деле вычислить труднее, чем окончательную. Поэтому мы должны пропустить его. - person jfclavette; 23.04.2009
comment
@jfclavette: Мне любопытно узнать, почему вы думаете, что вычисление расстояния быстрее, чем abs (x1 - x2) ‹= (r1 + r2)› = abs (y1 - y2). - person Ignacio Vazquez-Abrams; 23.04.2009
comment
Хммм, я думал о целых числах, где вы в основном меняете 2 пресса на 3 мула. Для чисел с плавающей запятой abs дешев, так что вы правы, что на самом деле он может быть быстрее. По-прежнему не думает, что это того стоит для чего-то, что уже имеет эффективный жесткий тест на столкновение. - person jfclavette; 23.04.2009

Обнаружение столкновений хорошо описано в ответе Пакса. Что касается отскока объектов друг от друга, я предлагаю проверить следующие ссылки, касающиеся эластичных столкновений , неупругие столкновения и коэффициенты восстановления.

РЕДАКТИРОВАТЬ: Я только что заметил, что это было описано в другом ТАК вопрос, хотя и не специально для Python. Вы также должны проверить там несколько хороших ссылок.

person gnovice    schedule 23.04.2009

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

Вызов функции get_rect может установить, вероятно, границы для изображений, а созданный Rect используется для вычисления положения изображения, а если в анимации присутствует более одного объекта, его можно использовать для обнаружения столкновений.

colliderect & rect можно использовать, проблема в том, что я понятия не имею, как вы бы это реализовали, особенно для неизвестного количества мячей.

Имея в виду, что это питон.

person savannah    schedule 23.04.2009

Еще в старые добрые времена, когда циклы ЦП были премиум-класса, кодировщики использовали простой трюк для обнаружения столкновений: они использовали такие цвета, которые можно было определить по цвету пикселя, фон это или объект. Это было сделано по крайней мере в некоторых играх для C64.

Но не знаю, готовы ли вы пойти по этому пути ...

person Makis    schedule 23.04.2009

Для начала нужно проверить коллизию с rect.colliderect(other_rect)

после этого, если они сталкиваются, вы можете проверить идеальное столкновение пикселей. Таким образом, вы не будете связываться с радиусом или формой объекта.

Для проверки идеального столкновения пикселей я использую маски: создайте оба объекта маски с помощью mask.from_surface, затем поместите их в функцию Mask.overlap.

person dhalsim    schedule 17.07.2009

Я сделал оператор if для обнаружения столкновений python, вот он:

if beach ball 1 x < beach ball 2 x + beach ball 1 width and beach ball 1 x + beach ball 2 width > beach ball 2 x and beach ball 1 y < beach ball 2 y + beach ball 1 height and beach ball 2 height + beach ball 1 y > beach ball 2 y:
    #put needed code here

В вашем случае с 3 прыгающими шарами вам нужно будет сделать 2 оператора if этого формата для каждого шара, чтобы убедиться, что обнаружение столкновений безупречно. Надеюсь, это поможет.

person pi guy    schedule 21.08.2016