2009-04-23 4 views
7

Ho codificato un'animazione (in python) per far sì che tre palloni da spiaggia rimbalzino sullo schermo. Ora desidero che tutti si scontrino e siano in grado di rimbalzarsi l'un l'altro. Gradirei davvero qualsiasi aiuto che possa essere offerto.Come posso creare rilevamenti di collisioni per le mie palle rimbalzanti?

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

possibile duplicato di [Collisione palla a sfera - Rilevazione e gestione] (http://stackoverflow.com/questions/345838/ball-to-ball-collision-detection-and-handling) – sarnold

+0

Ho fatto una domanda simile per un po ' fa: [Rilevamento e gestione delle collisioni [Ball to Ball]] (http://stackoverflow.com/questions/345838/ball-to-ball-collision-detection-and-handling) Ci sono state anche delle buone risposte. – mmcdole

risposta

10

Il rilevamento di collisioni per forme arbitrarie è in genere piuttosto complicato in quanto è necessario capire se un pixel collide.

Questo è in realtà più semplice con le cerchie. Se hai due cerchi di raggio r1 e r2, si è verificata una collisione se la distanza tra i centri è inferiore a r1 + r2.

La distanza tra i due centri (x1, y1) e (x2, y2) può essere calcolata e confrontata come:

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

Oppure, come sottolinea jfclavette, radici quadrate sono costosi quindi potrebbe essere meglio per calcolare utilizzando operazioni solo semplici:

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

la parte difficile viene nel calcolo dei nuovi vettori di movimento (il tasso al quale (x, y) cambia nel tempo per un determinato oggetto) dal momento che è necessario prendere in considerazione i vettori di movimento attuali e il punto di contatto.

Penso che come primo taglio, dovresti semplicemente invertire i vettori di movimento per verificare se il rilevamento delle collisioni funziona prima.

Poi fai un'altra domanda: è meglio mantenere specifiche domande specifiche in modo che le risposte possano essere mirate.

+3

Solo una nota: le radici quadrate sono operazioni piuttosto costose e puoi compensare entrambi i lati dell'equazione in quanto entrambi sono positivi. Questo ti dà d^2 = (y2-y1) * (y2-y1) + (x2-x1) * (x2-x1) e (d^2 <(r1 + r2)^2) come test. – jfclavette

+0

Buon punto, @jfclavette, soprattutto se si desidera il massimo frame/sec, incorporato nella risposta. – paxdiablo

3

Rilevare una collisione è solo il primo passo. Let's abbattere questo.

La cosa più veloce da fare è calcolare le caselle di delimitazione quadrate e vedere se quelle si scontrano. Due lati devono essere incrociati (in alto a 1 e in basso o in 2, a sinistra in 1 e a destra in 2 o viceversa) in modo da sovrapporre le caselle di delimitazione. Nessuna sovrapposizione, nessuna collisione.

Ora, quando si sovrappongono , è necessario calcolare la distanza tra di loro. Se questa distanza è maggiore delle somme dei raggi delle palle, allora nessuna collisione.

OK! Abbiamo due palle in collisione. Ora cosa? Beh, devono rimbalzarsi l'un l'altro. In che modo rimbalzano dipende da alcuni fattori.

Il primo è la loro elasticità. Due palline di gomma rimbalzano l'una contro l'altra in modo diverso rispetto a due sfere di vetro.

Il secondo è la loro velocità iniziale. L'inerzia afferma che vorranno continuare ad andare nella stessa direzione in cui hanno iniziato.

Il terzo è la massa delle sfere. Una palla con una massa più piccola rimbalza su una massa molto più grande con una velocità maggiore.

Trattiamo prima il secondo e il terzo fattore, poiché sono intrecciati.

Due palline raramente colpiscono perfettamente. I colpi di scherma sono molto più probabili. In ogni caso, l'impatto avverrà lungo la normale della tangente in cui le sfere si scontrano. È necessario calcolare la componente vettoriale di entrambi lungo questo normale, date le loro velocità iniziali. Ciò comporterà una coppia di velocità normali che entrambe le sfere porteranno alla collisione. Sommare la somma e conservarla in un posto a portata di mano.

Ora dobbiamo capire che cosa ogni pallina toglierà. La velocità normale risultante di ogni palla è inversamente proporzionale alla massa della palla data. Vale a dire, prendere il reciproco della massa di ciascuna palla, sommare entrambe le masse e quindi parzializzare la risultante velocità normale lontano dalla collisione in base al rapporto tra la massa della sfera e la somma del reciproco di entrambe le masse della palla. Quindi aggiungi la velocità tangenziale a questa e ottieni la velocità risultante della palla.

L'elasticità è quasi sempre la stessa, ma richiede un calcolo di base dovuto al fatto che le sfere si muovono ancora mentre si comprimono. Lo lascerò a te per trovare la matematica pertinente.

+0

La collisione cerchio/cerchio è più semplice del riquadro di delimitazione allineato all'asse del riquadro di delimitazione allineato all'asse. Basta saltare la parte relativa ai riquadri di delimitazione :) – jfclavette

+1

@jfclavette: Penso che stesse usando i riquadri di delimitazione come un primo controllo più facile da calcolare per una potenziale collisione prima di calcolare le distanze. – gnovice

+0

@gnovice: Sì, l'ho capito. Ma Sphere/Sphere o Circle/Circle è più veloce di Box/Box. Il primo controllo è infatti più difficile da calcolare rispetto al controllo finale. Dovremmo quindi saltarlo. – jfclavette

1

Penso che ci sia qualcosa di più semplice che voi ragazzi manchi soprattutto considerando che sta usando pygame.

La chiamata alla funzione get_rect può impostare probabilmente i limiti per le immagini e Rect che viene creata, viene utilizzata per calcolare la posizione dell'immagine e se ci sono più di un oggetto nell'animazione, può essere utilizzata per rilevare le collisioni.

colliderect & può essere utilizzato, il problema è non ho idea di come si dovrebbe implementarlo in particolare per un numero sconosciuto di palle.

Tenendo presente che è python.

0

Indietro nei bei tempi in cui i cicli della CPU erano un codificatore premium utilizzato un semplice trucco per rilevare la collisione: hanno usato tali colori che potevano distinguere dal colore del pixel se fosse sfondo o un oggetto. Questo è stato fatto su almeno alcuni giochi C64.

Non so se si è disposti a seguire questa strada, anche se ..

0

In primo luogo è necessario controllare la collisione con rect.colliderect(other_rect)

dopo che se sono in collisione, è possibile controllare pixel perfetta collisione. Quindi non si scherza con il raggio o la forma dell'oggetto.

Per il controllo perfetto della collisione con pixel, utilizzo le maschere: Realizza entrambi gli oggetti maschera con mask.from_surface, quindi inseriscili nella funzione Mask.overlap.

0

ho fatto un rilevamento pitone collisione if, eccolo:

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 

Nel tuo caso, con 3 palle che rimbalzano, si dovrà fare 2 se dichiarazioni di questo formato per ogni palla per assicurarsi che il rilevamento delle collisioni è impeccabile. Spero che aiuti.