Как создать обнаружение столкновений для моих прыгающих шаров? - PullRequest
7 голосов
/ 23 апреля 2009

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

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()

Ответы [ 7 ]

10 голосов
/ 23 апреля 2009

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

Это на самом деле проще с кругами. Если у вас есть два круга радиуса 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) изменяется со временем для данного объекта), поскольку вам необходимо учитывать текущие векторы движения и точку контакта. *

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

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

3 голосов
/ 23 апреля 2009

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

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

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

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

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

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

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

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

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

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

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

1 голос
/ 23 апреля 2009

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

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

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

Помня, что это питон.

1 голос
/ 23 апреля 2009

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

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

0 голосов
/ 21 августа 2016

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

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 этого формата для каждого шара, чтобы убедиться, что обнаружение столкновения безупречно. Надеюсь, это поможет.

0 голосов
/ 17 июля 2009

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

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

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

0 голосов
/ 23 апреля 2009

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

Не знаю, хотите ли вы идти по этому пути, хотя ..

...