2015-03-19 1 views
5

J'ai un programme dans lequel les cercles peuvent rebondir les uns sur les autres. J'ai suivi les instructions d'ici pour faire tourner les vecteurs et mise à l'échelle des grandeurs en fonction de l'angle de collision: http://www.vobarian.com/collisions/2dcollisions2.pdfJe ne trouve pas ce qui ne va pas avec ce calcul de rebond de cercle en python

j'ai écrit ce code en python (l'indice 0 indique la coordonnée x):

norm_vect = [(object2.pos[0] - object1.pos[0]), (object2.pos[1] - object1.pos[1])] 
unit = sqrt((norm_vect[0]**2) + (norm_vect[1]**2)) 
unit_vect = [float(norm_vect[0])/unit, float(norm_vect[1]) /unit] 
tan_vect = [-unit_vect[1], unit_vect[0]] 
vel1 = object1.vel 
vel2 = object2.vel 
vel1_norm = vel1[0] * unit_vect[0] + vel1[1] * unit_vect[1] 
vel1_tan = vel1[0] * tan_vect[0] + vel1[1] * tan_vect[1] 
vel2_norm = vel2[0] * unit_vect[0] + vel2[1] * unit_vect[1] 
vel2_tan = vel2[0] * tan_vect[0] + vel2[1] * tan_vect[1] 
new_vel1_norm = (vel1_norm * (object1.mass - object2.mass) + 2 * object2.mass * vel2_norm)/(object1.mass + object2.mass) 
new_vel2_norm = (vel2_norm * (object2.mass - object1.mass) + 2 * object1.mass * vel1_norm)/(object1.mass + object2.mass) 
new_norm_vect1 = [new_vel1_norm * float(unit_vect[0]), new_vel1_norm * float(unit_vect[1])] 
new_norm_vect2 = [new_vel2_norm * float(unit_vect[0]), new_vel2_norm * float(unit_vect[1])] 
new_tan_vect1 = [new_vel1_norm * float(tan_vect[0]), new_vel1_norm * float(tan_vect[1])] 
new_tan_vect2 = [new_vel2_norm * float(tan_vect[0]), new_vel2_norm * float(tan_vect[1])] 

# Now update the object's velocity 
object1.vel = [new_norm_vect1[0] + new_tan_vect1[0], + new_norm_vect1[1] + new_tan_vect1[1]] 
object2.vel = [new_norm_vect2[0] + new_tan_vect2[0], + new_norm_vect2[1] + new_tan_vect2[1]] 

Le problème c'est que ça marche parfois, mais pas d'autres fois. Quelqu'un peut-il me dire pourquoi? Il semble que si les balles entrent en collision à angle droit, alors leurs trajectoires de sortie s'échangent ou quelque chose. Je l'ai écrit dans le navigateur codeskulptor: http://www.codeskulptor.org/#user39_8q0Xdp3Y4s_2.py

Quelqu'un peut-il signaler où je me suis trompé?

EDIT: Est-ce que ça pourrait être la façon dont je traite la collision? Voici les étapes:

1) Draw the balls on the screen 
    2) Create set of unique pairs of collidable objects 
    3) For each ball, move the ball's position 1 frame forward according to the velocity: 
     ->1) Check to see if the ball is hitting a wall 
     ->2) For each pairset, if the ball in question is a member of the pair: 
      -->1) If distance between centers is less than sum of radii: 
        -->1) Calculate rebound trajectories 
        ---2) Find N such that position + rebound trajectory *N is out of collision zone 
+1

qu'est-ce que object2.2 sur votre dernière ligne? –

+0

une faute de frappe :) J'ai le code réel un peu différent d'interagir avec mes classes, j'ai donc dû en réécrire ici. Manqué celui-là! – Apc0243

+0

Si vous voulez juste résoudre le problème et que vous ne vous souciez pas de le résoudre à partir des principes de base, vous pouvez simplement utiliser un moteur physique à la place. –

Répondre

2

La simulation en ligne est vraiment cool! Je n'ai pas étudié votre code complet en détail, juste l'extrait que vous avez posté dans votre question. D'un coup d'œil, vous calculez correctement les vecteurs unitaires tangentiels et normaux, les anciennes vitesses normales et tangentielles et la nouvelle vitesse normale. Mais après cela, vous semblez vous perdre un peu. Comme expliqué dans le document sur les collisions, les vitesses tangentielles ne changent pas pendant la collision, il n'est donc pas nécessaire de calculer new_tan_vect1/2. Je ne comprends pas non plus pourquoi vous calculez new_norm_vect1, le vecteur normal ne change pas pendant la collision.

Quelques autres petites remarques:

  • pourquoi utilisez-vous float() tout votre code? Ce n'est normalement pas nécessaire. Si la raison en est d'obtenir des résultats corrects pour la division, vous devriez vraiment ajouter un from __future__ import division en haut de votre code, puisque vous semblez utiliser Python2. Voir this old question pour plus d'informations. Ce que vous appelez norm_vect est en fait le vecteur normal non normalisé, et ce que vous appelez unit_vect est en fait le vecteur unitaire normal normalisé. J'appellerais simplement les deux norm_vect, pour faire la différence entre normal et tangentiel plus clair. Un vecteur unitaire est n'importe quel vecteur de longueur 1, donc l'utiliser pour le vecteur normal est un peu trompeur.

  • Si vous envisagez de faire plus de ce genre de simulations, vous devriez envisager d'en apprendre davantage sur numpy. Cela vous permet d'écrire des calculs vectorisés, au lieu d'écrire toutes les équations pour x et y à la main. Par exemple. norm_vect = pos2 - pos1; norm_vect /= np.linalg.norm(norm_vect) ou object1.vel = norm_vect * new_vel1_norm + tang_vect * vel1_tang.

Je voudrais écrire votre extrait devrait plus ou moins comme celui-ci (code non testé):

from __future__ import division # move this to the top of your program 

# calculate normal and tangential unit vectors 
norm_vect = [(object2.pos[0] - object1.pos[0]), 
      (object2.pos[1] - object1.pos[1])] # stil un-normalized! 
norm_length = sqrt((norm_vect[0]**2) + (norm_vect[1]**2)) 
norm_vect = [norm_vect[0]/norm_length, 
      norm_vect[1]/norm_length] # do normalization 
tang_vect = [-norm_vect[1], norm_vect[0]] # rotate norm_vect by 90 degrees 

# normal and tangential velocities before collision 
vel1 = object1.vel 
vel2 = object2.vel 
vel1_norm = vel1[0] * norm_vect[0] + vel1[1] * norm_vect[1] 
vel1_tang = vel1[0] * tang_vect[0] + vel1[1] * tang_vect[1] 
vel2_norm = vel2[0] * norm_vect[0] + vel2[1] * norm_vect[1] 
vel2_tang = vel2[0] * tang_vect[0] + vel2[1] * tang_vect[1] 

# calculate velocities after collision 
new_vel1_norm = (vel1_norm * (object1.mass - object2.mass) 
    + 2 * object2.mass * vel2_norm)/(object1.mass + object2.mass) 
new_vel2_norm = (vel2_norm * (object2.mass - object1.mass) 
    + 2 * object1.mass * vel1_norm)/(object1.mass + object2.mass) 
# no need to calculate new_vel_tang, since it does not change 

# Now update the object's velocity 
object1.vel = [norm_vect[0] * new_vel1_norm + tang_vect[0] * vel1_tang, 
       norm_vect[1] * new_vel1_norm + tang_vect[1] * vel1_tang] 
object2.vel = [norm_vect[0] * new_vel2_norm + tang_vect[0] * vel2_tang, 
       norm_vect[1] * new_vel2_norm + tang_vect[1] * vel2_tang] 

Je renommé certaines variables pour le rendre plus clair.

+0

Eh bien maintenant j'ai l'impression que je corrige quelque chose en python parce que les vélocités changent mais pour une raison quelconque, l'état global de la classe n'est pas changé. Voir ici: http://www.codeskulptor.org/#user39_8q0Xdp3Y4s_3.py Se pourrait-il que je ne puisse pas importer depuis '__future__' car codeskulptor est une implémentation extrêmement limitée de Python juste pour que les gens puissent apprendre les bases de l'interaction (module simpleGUI créé par les professeurs de la classe Coursera avec codeskulptor) – Apc0243

+0

http://www.codeskulptor.org/#user39_8q0Xdp3Y4s_4.py <- que l'on est plus propre mais le problème est toujours là et je n'ai aucune idée pourquoi. Je pense que c'est parce que ma fonction collision() est appelée par une méthode de classe. Je ne suis pas sûr de savoir comment implémenter le contrôle de collision par paire à l'intérieur de la classe, c'est pourquoi je l'ai sorti – Apc0243

+1

En regardant les vitesses que vous imprimez dans la fonction de collision, il semblait que lorsqu'une balle légère entrait en collision avec une balle lourde, la vélocité tournait comme elle le devait, mais ensuite, tout de suite après, elle tournait à nouveau dans la direction opposée, si bien que rien ne se passait. L'erreur était dans votre fonction 'match_objects', vous ajoutez chaque paire deux fois, une fois en avant et une fois en arrière. Chaque collision est alors détectée deux fois, à partir de object1 et pour object2, ces deux s'annulent mutuellement. Cela semble fonctionner (les boules se coincent parfois): http://www.codeskulptor.org/#user39_sV5TmqJSlAYGeOG.py –