Comment faire ricocher des Balles entre elles.
Résolu/Fermé
Pulsar360
Messages postés
113
Date d'inscription
lundi 12 novembre 2012
Statut
Membre
Dernière intervention
29 août 2018
-
Modifié par Pulsar360 le 6/04/2013 à 19:09
KX Messages postés 16753 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 25 novembre 2024 - 14 avril 2013 à 20:09
KX Messages postés 16753 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 25 novembre 2024 - 14 avril 2013 à 20:09
A voir également:
- Comment faire ricocher des Balles entre elles.
- Dragon ball z budokai tenkaichi 3 comment avoir goku god ✓ - Forum Jeux vidéo
- Comment degonfler une balle de basket ✓ - Forum Loisirs / Divertissements
- Dragon ball z budokai tenkaichi 3 astuce - Forum Jeux vidéo
- Comment télécharger dragon ball z - Forum Téléchargement
- Que faire avec balles de paille dans farming simulator - Forum Jeux PC
3 réponses
KX
Messages postés
16753
Date d'inscription
samedi 31 mai 2008
Statut
Modérateur
Dernière intervention
25 novembre 2024
3 019
14 avril 2013 à 20:09
14 avril 2013 à 20:09
En faisant cela bien :
Je pars toujours de l'article de Wikipédia sur les Chocs élastiques, mais en faisant bien attention car le code fourni est un cas particulier lorsque toutes les masses sont identiques, j'avais essayé de l'adapter au cas où il y avait des masses différentes, mais mes calculs étaient faux.
Après avoir fait un peu plus attention, voici les bons calculs.
PS. j'ai laissé en commentaire les calculs qui permettent de vérifier que c'est bon.
Remarque :
Ce calcul n'est valable qu'au moment exact où on a le ricochet, c'est à dire que les deux balles sont séparées d'une distance r = b1.r + b2.r
Or en pratique, le déplacement est généralement effectué sur un pas de temps discret, c'est à dire avec un code comme ceci :
Il y a donc un problème, parce que s'il y a collision entre deux balles, c'est très certainement en plein milieu de ce temps "dt", il faudrait donc pouvoir appeler la méthode de collision au bon moment. Je propose pour cela de "remonter le temps".
Première étape (la plus facile), deux balles sont en collisions si leur distance est égale (ou inférieure) à la somme de leur rayon. Cela se calcule comme ça :
Ensuite, supposons que b1 et b2 soient détectées en collision, cela signifie qu'avant qu'on les déplace de "dt" elles ne l'étaient pas, mais qu'après ce déplacement elles le sont. On va donc remonter le temps de "dt" puis avancer progressivement jusqu'au temps "exact" où la collision s'est produit.
Pour calculer le temps "exact" où se produit la collision je propose de procéder par dichotomie, on cherche donc (entre 0 et dt) la valeur de "t" tel qu'on ait la distance "r" entre b1 et b2 qui soit égale à b1.r + b2.r
Remarque : je dis temps "exact" avec des guillemets, car en réalité je vais tolérer une petite marge d'erreur (par exemple de 1e-9)
Voici ce que donnerait le calcul :
Une fois ce temps obtenu, il s'agit "simplement" de faire avancer normalement les deux balles jusqu'à la collision, puis traiter la collision, et enfin continuer leur déplacement après la collision du temps qu'il reste.
Et comme ceci, on se retrouve avec des collisions physiquement réalistes...
Voici un exemple complet de balles qui se déplacent dans une fenêtre.
Remarque : les calculs de rebonds sur les bords pourraient être améliorés de la même manière, mais j'ai surtout insisté sur le rebond des balles entre elles.
Je pars toujours de l'article de Wikipédia sur les Chocs élastiques, mais en faisant bien attention car le code fourni est un cas particulier lorsque toutes les masses sont identiques, j'avais essayé de l'adapter au cas où il y avait des masses différentes, mais mes calculs étaient faux.
Après avoir fait un peu plus attention, voici les bons calculs.
PS. j'ai laissé en commentaire les calculs qui permettent de vérifier que c'est bon.
public class Balle { /** Rayon de la balle. */ protected final double r; /** Masse de la balle. */ protected final double m; /** Position de la balle. */ protected double x,y; /** Vitesse de la balle. */ protected double vx,vy; /** * Modifies les vecteurs vitesses de deux balles qui entrent en collision. */ protected static final void collision(Balle b1, Balle b2) { // Quantité de mouvement et énergie cinétique avant la collision //double qmx1 = b1.m * b1.vx + b2.m * b2.vx; //double qmy1 = b1.m * b1.vy + b2.m * b2.vy; //double ec1 = b1.m * (b1.vx*b1.vx + b1.vy*b1.vy) + b2.m * (b2.vx*b2.vx + b2.vy*b2.vy); // Calcul de la base orthonormée (n,g) double dx = b1.x - b2.x; double dy = b1.y - b2.y; double r = Math.sqrt(dx*dx + dy*dy); // n est perpendiculaire au plan de collision double nx = (b2.x - b1.x) / r; double ny = (b2.y - b1.y) / r; // g est tangent au plan de collision double gx = -ny; double gy = nx; // Transition des vitesses de la base (x,y) vers (n,g) double v1n = nx*b1.vx + ny*b1.vy; double v1g = gx*b1.vx + gy*b1.vy; double v2n = nx*b2.vx + ny*b2.vy; double v2g = gx*b2.vx + gy*b2.vy; // Détermination des nouvelles vitesses dans (n,g) double m = b1.m + b2.m; double m12 = (b1.m - b2.m)/m; double m22 = (b2.m + b2.m)/m; double m11 = (b1.m + b1.m)/m; double m21 = (b2.m - b1.m)/m; double v1n2 = m12*v1n + m22*v2n; double v1g2 = m12*v1g + m22*v2g; double v2n2 = m11*v1n + m21*v2n; double v2g2 = m11*v1g + m21*v2g; // Modification des vitesses dans la base (x,y) b1.vx = nx*v1n2 + gx*v1g2; b1.vy = ny*v1n2 + gy*v1g2; b2.vx = nx*v2n2 + gx*v2g2; b2.vy = ny*v2n2 + gy*v2g2; // Quantité de mouvement et énergie cinétique après la collision //double qmx2 = b1.m * b1.vx + b2.m * b2.vx; //double qmy2 = b1.m * b1.vy + b2.m * b2.vy; //double ec2 = b1.m * (b1.vx*b1.vx + b1.vy*b1.vy) + b2.m * (b2.vx*b2.vx + b2.vy*b2.vy); //Vérification de la conservation de la quantité de mouvement et de l'énergie cinétique //System.out.printf("%.2f = %.2f\t%.2f = %.2f\t%.2f = %.2f\n",qmx1,qmx2,qmy1,qmy2,ec1,ec2); } }
Remarque :
Ce calcul n'est valable qu'au moment exact où on a le ricochet, c'est à dire que les deux balles sont séparées d'une distance r = b1.r + b2.r
Or en pratique, le déplacement est généralement effectué sur un pas de temps discret, c'est à dire avec un code comme ceci :
/** * Modifie la position de la balle en fonction de sa vitesse. * @param dt durée du déplacement */ protected void deplacement(double dt) { x += vx * dt; y += vy * dt; }
Il y a donc un problème, parce que s'il y a collision entre deux balles, c'est très certainement en plein milieu de ce temps "dt", il faudrait donc pouvoir appeler la méthode de collision au bon moment. Je propose pour cela de "remonter le temps".
Première étape (la plus facile), deux balles sont en collisions si leur distance est égale (ou inférieure) à la somme de leur rayon. Cela se calcule comme ça :
/** * @return true si les deux balles sont en collision */ protected static boolean sontCollision(Balle b1, Balle b2) { double dx = b1.x-b2.x, dy = b1.y-b2.y, r = b1.r+b2.r; return dx*dx + dy*dy <= r*r; }
Ensuite, supposons que b1 et b2 soient détectées en collision, cela signifie qu'avant qu'on les déplace de "dt" elles ne l'étaient pas, mais qu'après ce déplacement elles le sont. On va donc remonter le temps de "dt" puis avancer progressivement jusqu'au temps "exact" où la collision s'est produit.
// On remonte le temps b1.deplacement(-dt); b2.deplacement(-dt);
Pour calculer le temps "exact" où se produit la collision je propose de procéder par dichotomie, on cherche donc (entre 0 et dt) la valeur de "t" tel qu'on ait la distance "r" entre b1 et b2 qui soit égale à b1.r + b2.r
Remarque : je dis temps "exact" avec des guillemets, car en réalité je vais tolérer une petite marge d'erreur (par exemple de 1e-9)
Voici ce que donnerait le calcul :
double tps = tpsCollision(b1,b2,0,dt,1e-9); /** * @return t tel que distance(b1,b2) = b1.r+b2.r */ private static double tpsCollision(Balle b1, Balle b2, double t0, double t2, double e) { double t1 = (t0+t2)/2; if (t2-t0<e) return t1; else { if (Math.pow((b1.x+b1.vx*t1)-(b2.x+b2.vx*t1),2) + Math.pow((b1.y+b1.vy*t1)-(b2.y+b2.vy*t1),2) > Math.pow(b1.r+b2.r,2)) return tpsCollision(b1,b2,t1,t2,e); else return tpsCollision(b1,b2,t0,t1,e); } }
Une fois ce temps obtenu, il s'agit "simplement" de faire avancer normalement les deux balles jusqu'à la collision, puis traiter la collision, et enfin continuer leur déplacement après la collision du temps qu'il reste.
// déplacement des balles jusqu'à la collision b1.deplacement(tps); b2.deplacement(tps); // traitement de la collision collision(b1,b2); // déplacement des balles après la collision b1.deplacement(dt-tps); b2.deplacement(dt-tps);
Et comme ceci, on se retrouve avec des collisions physiquement réalistes...
Voici un exemple complet de balles qui se déplacent dans une fenêtre.
Remarque : les calculs de rebonds sur les bords pourraient être améliorés de la même manière, mais j'ai surtout insisté sur le rebond des balles entre elles.
import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Graphics; import java.util.Random; import javax.swing.JFrame; class Balle { /** Rayon de la balle. */ protected final double r; /** Masse de la balle. */ protected final double m; /** Position de la balle. */ protected double x,y; /** Vitesse de la balle. */ protected double vx,vy; protected final Color clr; public Balle(double r, double x0, double y0, double vx0, double vy0, Color clr) { this.r = r; this.m = Math.pow(r,3); this.clr = clr; x=x0; y=y0; vx=vx0; vy=vy0; } /** * Déplace toutes les balles dans le plan et gère les collisions. * @param width largeur du plan * @param height hauteur du plan * @param dt durée du déplacement * @param balles toutes les balles du plan */ public static void deplacer(double width, double height, double dt, Balle...balles) { for (Balle balle : balles) { balle.deplacement(dt); balle.contactAuxBords(width,height); } for (int i=0, n=balles.length; i<n; i++) for (int j=i+1; j<n; j++) { if (sontCollision(balles[i],balles[j])) { Balle b1 = balles[i], b2=balles[j]; // on remonte le temps (on annule le dernier déplacement qui va conduire à une collision) b1.deplacement(-dt); b2.deplacement(-dt); // calcul du temps "exact" de la collision double tps = tpsCollision(b1,b2,0,dt,1e-9); // déplacement des balles jusqu'à la collision b1.deplacement(tps); b2.deplacement(tps); // traitement de la collision collision(b1,b2); // déplacement des balles après la collision b1.deplacement(dt-tps); b2.deplacement(dt-tps); } } } /** * Modifie la position de la balle en fonction de sa vitesse. * @param dt durée du déplacement */ protected void deplacement(double dt) { x += vx * dt; y += vy * dt; } /** * Gère le contact d'une balle sur un bord du plan. * @param width largeur du plan * @param height hauteur du plan */ protected void contactAuxBords(double width, double height) { if (x-r < 0) { x = r; vx = -vx; } else if (x+r > width) { x = width-r; vx = -vx; } if (y-r < 0) { y = r; vy = -vy; } else if (y+r > height) { y = height-r; vy = -vy; } } /** * @return true si les deux balles sont en collision */ protected static boolean sontCollision(Balle b1, Balle b2) { double dx = b1.x-b2.x, dy = b1.y-b2.y, r = b1.r+b2.r; return dx*dx + dy*dy <= r*r; } /** * @return t tel que distance(b1,b2) = b1.r+b2.r */ private static double tpsCollision(Balle b1, Balle b2, double t0, double t2, double e) { double t1 = (t0+t2)/2; if (t2-t0<e) return t1; else { if (Math.pow((b1.x+b1.vx*t1)-(b2.x+b2.vx*t1),2)+Math.pow((b1.y+b1.vy*t1)-(b2.y+b2.vy*t1),2) > Math.pow(b1.r+b2.r,2)) return tpsCollision(b1,b2,t1,t2,e); else return tpsCollision(b1,b2,t0,t1,e); } } /** * Modifies les vecteurs vitesses de deux balles qui entrent en collision. */ protected static final void collision(Balle b1, Balle b2) { // Quantité de mouvement et énergie cinétique avant la collision //double qmx1 = b1.m * b1.vx + b2.m * b2.vx; //double qmy1 = b1.m * b1.vy + b2.m * b2.vy; //double ec1 = b1.m * (b1.vx*b1.vx + b1.vy*b1.vy) + b2.m * (b2.vx*b2.vx + b2.vy*b2.vy); // Calcul de la base orthonormée (n,g) double dx = b1.x - b2.x; double dy = b1.y - b2.y; double r = Math.sqrt(dx*dx + dy*dy); // n est perpendiculaire au plan de collision double nx = (b2.x - b1.x) / r; double ny = (b2.y - b1.y) / r; // g est tangent au plan de collision double gx = -ny; double gy = nx; // Transition des vitesses de la base (x,y) vers (n,g) double v1n = nx*b1.vx + ny*b1.vy; double v1g = gx*b1.vx + gy*b1.vy; double v2n = nx*b2.vx + ny*b2.vy; double v2g = gx*b2.vx + gy*b2.vy; // Détermination des nouvelles vitesses dans (n,g) double m = b1.m + b2.m; double m12 = (b1.m - b2.m)/m; double m22 = (b2.m + b2.m)/m; double m11 = (b1.m + b1.m)/m; double m21 = (b2.m - b1.m)/m; double v1n2 = m12*v1n + m22*v2n; double v1g2 = m12*v1g + m22*v2g; double v2n2 = m11*v1n + m21*v2n; double v2g2 = m11*v1g + m21*v2g; // Modification des vitesses dans la base (x,y) b1.vx = nx*v1n2 + gx*v1g2; b1.vy = ny*v1n2 + gy*v1g2; b2.vx = nx*v2n2 + gx*v2g2; b2.vy = ny*v2n2 + gy*v2g2; //Quantité de mouvement et énergie cinétique après la collision //double qmx2 = b1.m * b1.vx + b2.m * b2.vx; //double qmy2 = b1.m * b1.vy + b2.m * b2.vy; //double ec2 = b1.m * (b1.vx*b1.vx + b1.vy*b1.vy) + b2.m * (b2.vx*b2.vx + b2.vy*b2.vy); //Vérification de la conservation de la quantité de mouvement et de l'énergie cinétique //System.out.printf("%.2f = %.2f\t%.2f = %.2f\t%.2f = %.2f\n",qmx1,qmx2,qmy1,qmy2,ec1,ec2); } } public class Animation extends Component { private static final long serialVersionUID = 1; private final Balle[] balles; private final Thread daemon; public Animation(final Dimension dim, final int nbBalles, final double rMax, final double v0, final long freq, final double dt) { Random random = new Random(); balles = new Balle[nbBalles]; for (int i=0; i<nbBalles; i++) { balles[i] = new Balle(random.nextDouble()*rMax, random.nextDouble()*dim.width, random.nextDouble()*dim.height, random.nextDouble()*v0, random.nextDouble()*v0, new Color(Color.HSBtoRGB(random.nextFloat(), 1f, 0.85f))); } daemon = new Thread() { @Override public void run() { while (true) { if (isInterrupted()) return; Balle.deplacer(dim.getWidth(), dim.getHeight(), dt, balles); repaint(); try { Thread.sleep(freq); } catch (InterruptedException e) { return; } } } }; daemon.setDaemon(true); setSize(dim); } public void start() { daemon.start(); } public void stop() { daemon.interrupt(); } @Override public void paint(Graphics g) { for (Balle b : balles) { g.setColor(b.clr); g.fillOval((int) (b.x-b.r), (int) (b.y-b.r), (int) (2*b.r), (int) (2*b.r)); } } public static void main(String[] args) { JFrame frame = new JFrame(); frame.setExtendedState(JFrame.MAXIMIZED_BOTH); frame.setVisible(true); Animation animation = new Animation(frame.getSize(), 10, 50, 10, 50, 1); frame.add(animation); animation.start(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } }
KX
Messages postés
16753
Date d'inscription
samedi 31 mai 2008
Statut
Modérateur
Dernière intervention
25 novembre 2024
3 019
7 avril 2013 à 03:02
7 avril 2013 à 03:02
J'ai adapté le calcul présenté sur l'article Chocs élastique de Wikipédia en fonction de tes contraintes, si tu as des questions théoriques je t'invite donc à lire cet article.
Pour le code en Java, tu devras bien sûr l'adapter en fonction de ce que tu as déjà.
Pour le code en Java, tu devras bien sûr l'adapter en fonction de ce que tu as déjà.
public class Balle { /** Rayon de la balle. */ protected final double r; /** Masse de la balle. */ protected final double m; /** Position de la balle. */ protected double x,y; /** Vitesse de la balle. */ protected double vx,vy; /** * Modifie la position de la balle en fonction de sa vitesse. * @param dt durée du déplacement */ protected void deplacement(double dt) { x += vx * dt; y += vy * dt; } /** * Modifies les vecteurs vitesses de deux balles qui entrent en collision. */ protected static final void collision(Balle b1, Balle b2) { double nx = (b2.x - b1.x) / (b1.r+b2.r); double ny = (b2.y - b1.y) / (b1.r+b2.r); double gx = -ny; double gy = nx; double v1n = nx*b1.vx*(b1.m-b2.m)/(b1.m+b2.m) + ny*b2.vx*(2*b2.m)/(b1.m+b2.m); double v1g = gx*b1.vx*(b1.m-b2.m)/(b1.m+b2.m) + gy*b2.vx*(2*b2.m)/(b1.m+b2.m); double v2n = nx*b2.vx*(b2.m-b1.m)/(b1.m+b2.m) + ny*b1.vx*(2*b1.m)/(b1.m+b2.m); double v2g = gx*b2.vx*(b2.m-b1.m)/(b1.m+b2.m) + gy*b1.vx*(2*b1.m)/(b1.m+b2.m); b1.vx = nx*v2n + gx*v1g; b1.vy = ny*v2n + gy*v1g; b2.vx = nx*v1n + gx*v2g; b2.vy = ny*v1n + gy*v2g; } }
Pulsar360
Messages postés
113
Date d'inscription
lundi 12 novembre 2012
Statut
Membre
Dernière intervention
29 août 2018
10
7 avril 2013 à 08:44
7 avril 2013 à 08:44
Merci KX c'est parfait !!
+1
+1
KX
Messages postés
16753
Date d'inscription
samedi 31 mai 2008
Statut
Modérateur
Dernière intervention
25 novembre 2024
3 019
14 avril 2013 à 19:23
14 avril 2013 à 19:23
En fait c'était n'importe quoi ^^
Je vais faire une autre réponse pour expliquer comment faire ça bien ;-)
Je vais faire une autre réponse pour expliquer comment faire ça bien ;-)
KX
Messages postés
16753
Date d'inscription
samedi 31 mai 2008
Statut
Modérateur
Dernière intervention
25 novembre 2024
3 019
6 avril 2013 à 23:21
6 avril 2013 à 23:21
J'ai bien une petite idée, mais j'aimerais avoir quelques précisions avant de me lancer, est-ce que :
1) tes deux balles sont identiques ? (même taille, même poids...)
2) la vitesse est constante ? (est-ce que les balles peuvent ralentir, s'arrêter...)
3) tes deux balles vont à la même vitesse ?
4) tu veux juste une impression de réalisme, ou un calcul exact ?
1) tes deux balles sont identiques ? (même taille, même poids...)
2) la vitesse est constante ? (est-ce que les balles peuvent ralentir, s'arrêter...)
3) tes deux balles vont à la même vitesse ?
4) tu veux juste une impression de réalisme, ou un calcul exact ?
Pulsar360
Messages postés
113
Date d'inscription
lundi 12 novembre 2012
Statut
Membre
Dernière intervention
29 août 2018
10
7 avril 2013 à 01:02
7 avril 2013 à 01:02
Bonsoir,
1) Non mes deux balles ne sont pas identique (je vais utiliser des diamètres différent et des images pour les balles)
2) Non les vitesses ne seront pas constantes.
3) Les balles ne vont pas non plus à la même vitesse.
4) Ben j'avoue que j'aime la précision donc je veux bien des calculs exact mais au vue de mes réponse si je doit me contenter d'une impression ça ne seras pas trèèès grave.
Merci =)
1) Non mes deux balles ne sont pas identique (je vais utiliser des diamètres différent et des images pour les balles)
2) Non les vitesses ne seront pas constantes.
3) Les balles ne vont pas non plus à la même vitesse.
4) Ben j'avoue que j'aime la précision donc je veux bien des calculs exact mais au vue de mes réponse si je doit me contenter d'une impression ça ne seras pas trèèès grave.
Merci =)