Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
2910 connectés 

  FORUM HardWare.fr
  Programmation
  Algo

  Système de collision

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

Système de collision

n°1974017
alexandre_​j
Posté le 15-03-2010 à 19:32:47  profilanswer
 

Bonjour,
 
Je suis entrain de réaliser une petite application mettant en scène un certain nombres de billes se déplaçant dans un cadre. Elles seront soumises à un système de collision simple (choc élastique, que j'ai pu voir dans un autre topic).
 
Ma question est comment articuler tout ça ?
 
Aujourd'hui j'ai un vector de Billes et une bille possède une fonction du genre bille.estEnCollision(bille). Mon problème se situe un niveau au dessus, au niveau du système. Comment faire à chaque frame pour tester les collisions ? Parcourir le vector et tester pour chaque bille si elle est en collision avec les autres (Double boucle) ?
 
Où est-ce que la fonction estEnCollision doit être implémenter dans un manager de billes ?
 
J'ai pas trop d'idée sur la façon de structurer ce système de collision. Si vous avez des liens ou des articles, je suis preneur !
Merci de votre aide.

mood
Publicité
Posté le 15-03-2010 à 19:32:47  profilanswer
 

n°1974134
Kenelm
Posté le 16-03-2010 à 13:44:44  profilanswer
 

Y'a pas d'autre méthode que de comparer les collisions de chaque objet avec un autre.
Des moteurs physiques comme Havok, au plus simple de leur structure, fonctionnent comme ça. Tout ce qu'on peut faire ensuite, c'est améliorer la façon dont ça procède.
On peut couper l'espace en plusieurs zones, de façon à restreindre la recherche. Ou alors on peut juste regrouper les objets par petits groupes qui disposent alors d'une forme de collision simplifiée (genre un gros cube), car l'on sait que si un objet du groupe est touché, il y a des chances que les autres le soient aussi, ce qui s'étend ensuite aux groupes voisins. Ou alors tu peux simplifier le calcul... la méthode la plus simple consiste à effectuer le calcul sur des formes plus simples. Par exemple dans un Mario, chaque objet est un cube, mais les polygones ne sont pas gérés un par un. Ca simplifie le calcul de collision, et ça permet ainsi de mettre plus d'objets.

 

Quoi qu'il en soit, tu devras tester tous les cas possibles, il n'y a aucune parade à ça, et tu ne peux qu'optimiser ce processus. A toi de trouver la meilleure façon de procéder.

 

Ou alors y'a une méthode qui m'est inconnue qui permet de se passer ça, mais franchement, j'en doute...


Message édité par Kenelm le 16-03-2010 à 13:46:12
n°1974172
0x90
Posté le 16-03-2010 à 16:00:12  profilanswer
 

Commence par la méthode simple avant de tenter les facons plus complexes (uniquement utiles si t'as un grand nombre de billes).
 
Il faut faire effectivement toutes les paires, à chaque frame, mais il te faut juste éviter de faire les tests en double (a vs. b et b vs. a) sinon tu va répondre en double aux collisions (et gaspiller la moitié de ton temps).
 
Le "manager de bille" est une bonne idée, il devra aussi manager les collisions avec les bords de ton cadre.
 
Occupe toi en premier de répondre correctement aux collisions.
 
C'est déjà pas si simple d'avoir de bonnes réponses aux collisions si tu ne fais que des détections à intervales régulier, par ex. comment réagir correctement à un choc élastique si les billes ont eu le temps de se traverser presque entièrement ? et comment réagir quand un groupe de plus de deux billes se cognent simultanément ? si tu résous les collisions bêtement l'une après l'autre tu risque déjà de voir apparaitre d'étranges bugs.
 
Optimiser et tenter d'éviter les tests inutiles avec des indexes spatiaux & co. ça peut venir après (c'est pas facile de debugger si t'as un mélange de tests de collisions qui manquent et de réactions aux collisions buggées, un bug à la fois c'est moins pénible).


---------------
Me: Django Localization, Yogo Puzzle, Chrome Grapher, C++ Signals, Brainf*ck.
n°1974180
Kenelm
Posté le 16-03-2010 à 16:12:23  profilanswer
 

En toute logique, on a (presque) jamais plus de deux objets qui entrent en collision l'un dans l'autre. Y'en a (presque) toujours deux qui se heurtent avant l'arrivée du troisième.
 
En ce qui concerne la traversée, c'est effectivement un problème. Il y a deux méthodes pour déterminer ça, bien que je sache pas du tout ce que c'est que ce truc de choc élastique : la méthode discrète, et la méthode continue.
 
La méthode discrète consiste à calculer à chaque frame un nouvel état après mise à jour de la position de tous les objets. Bien évidemment, si un objet se déplace à une vitesse supérieure à sa taille divisée par le pas de temps, cet objet passera à travers tous les autres. Pour résoudre ce problème, une seule solution : diminuer le pas de temps, donc faire plus de calculs. C'est dans 100% des cas la cause des bugs de moteur physique dans les jeux, où l'on voit des trucs qui se comportent bizarrement, comme des corps coincés à travers un mur ou autres du genre. Mais si tu définis une limite à la vitesse et que la taille du plus petit objet divisée par le pas de temps est inférieure à cette vitesse, alors tu n'auras aucun problème.
 
La méthode continue consiste à prévoir les collisions à l'avance pour les gérer parfaitement, calcul qui doit être intégralement refait à chaque changement de condition, aussi petit soit-il. Ça revient à une méthode discrète avec un pas de temps infiniment petit. C'est bien évidemment bieeeeeeeeeen plus lourd à exécuter, et bien plus lent, mais par contre la gestion est parfaite.
 
Evidemment, je te conseille la méthode discrète, c'est bien plus simple à mettre en place, et suffisant pour des petites applications graphiques.

n°1974200
0x90
Posté le 16-03-2010 à 16:36:51  profilanswer
 

Kenelm a écrit :

En toute logique, on a (presque) jamais plus de deux objets qui entrent en collision l'un dans l'autre. Y'en a (presque) toujours deux qui se heurtent avant l'arrivée du troisième.


Avec une méthode discrète et quelques billes coincées dans un coin de cadre ça arrive à coup sûr (et y'a de grandes chances de voir les billes finir par s'agglutiner les unes contre les autres ou passer à travers les murs).

Kenelm a écrit :


En ce qui concerne la traversée, c'est effectivement un problème. Il y a deux méthodes pour déterminer ça, bien que je sache pas du tout ce que c'est que ce truc de choc élastique : la méthode discrète, et la méthode continue.
 
La méthode discrète consiste à calculer à chaque frame un nouvel état après mise à jour de la position de tous les objets. Bien évidemment, si un objet se déplace à une vitesse supérieure à sa taille divisée par le pas de temps, cet objet passera à travers tous les autres. Pour résoudre ce problème, une seule solution : diminuer le pas de temps, donc faire plus de calculs. C'est dans 100% des cas la cause des bugs de moteur physique dans les jeux, où l'on voit des trucs qui se comportent bizarrement, comme des corps coincés à travers un mur ou autres du genre. Mais si tu définis une limite à la vitesse et que la taille du plus petit objet divisée par le pas de temps est inférieure à cette vitesse, alors tu n'auras aucun problème.


Même avec une vitesse assez faible pour ne pas avoir de pénétration complète, avec des billes les angles de rebonds vont être pratiquement aléatoire (dans un impact avec des vecteurs non-colinénaires, un peu de retard et les centres des billes se décalent beaucoup, même si la pénétration est faible, et les centres des billes servant souvent à calculer l'angle de rebord, c'est la cata).

Kenelm a écrit :


La méthode continue consiste à prévoir les collisions à l'avance pour les gérer parfaitement, calcul qui doit être intégralement refait à chaque changement de condition, aussi petit soit-il. Ça revient à une méthode discrète avec un pas de temps infiniment petit. C'est bien évidemment bieeeeeeeeeen plus lourd à exécuter, et bien plus lent, mais par contre la gestion est parfaite.
 
Evidemment, je te conseille la méthode discrète, c'est bien plus simple à mettre en place, et suffisant pour des petites applications graphiques.


C'est juste une division et une racine carrée en plus pour savoir quand aura lieu une collision en plus de si elle a lieu. Y'a des complications pour avoir une résolution nickel ensuite, mais y'a aussi des méthodes à cout limité (en calcul et en code) qui améliorent déjà nettement la qualité des réponses.


---------------
Me: Django Localization, Yogo Puzzle, Chrome Grapher, C++ Signals, Brainf*ck.
n°1974216
Kenelm
Posté le 16-03-2010 à 16:50:34  profilanswer
 

0x90 a écrit :

Avec une méthode discrète et quelques billes coincées dans un coin de cadre ça arrive à coup sûr (et y'a de grandes chances de voir les billes finir par s'agglutiner les unes contre les autres ou passer à travers les murs). Même avec une vitesse assez faible pour ne pas avoir de pénétration complète, avec des billes les angles de rebonds vont être pratiquement aléatoire (dans un impact avec des vecteurs non-colinénaires, un peu de retard et les centres des billes se décalent beaucoup, même si la pénétration est faible, et les centres des billes servant souvent à calculer l'angle de rebord, c'est la cata).

Si la gestion des collisions est bien faite, y'a aucune raison que ça arrive. J'ai fait des animations de ce genre des tonnes de fois pour des projets à la con, j'ai jamais eu de problème franchement...
 

0x90 a écrit :

C'est juste une division et une racine carrée en plus pour savoir quand aura lieu une collision en plus de si elle a lieu. Y'a des complications pour avoir une résolution nickel ensuite, mais y'a aussi des méthodes à cout limité (en calcul et en code) qui améliorent déjà nettement la qualité des réponses.

Ah non c'est un peu plus compliqué, vu qu'une collision peut en cacher une autre :D
Il faut lister les collisions, les trier de façon temporelle, et ne conserver que la première, vu qu'elle va logiquement perturber toutes les suivantes, et tous ces calculs auront été faits pour rien... Mais c'est vrai que j'avais une optique davantage 3D pour ça, où là ça devient un peu plus tendu... en effet pour des billes, ça posera pas vraiment problème.

n°1974232
0x90
Posté le 16-03-2010 à 17:18:29  profilanswer
 

Kenelm a écrit :

Si la gestion des collisions est bien faite, y'a aucune raison que ça arrive. J'ai fait des animations de ce genre des tonnes de fois pour des projets à la con, j'ai jamais eu de problème franchement...


Ça dépends le genre d'anim, un grand festival de billes façon feux-d'artifice de particules ça passe nickel, par contre si y'a peu de billes et que l'utilisateur observe ou pire, doit jouer avec, il risque de pas aimer les collisions qui partent de travers.

Kenelm a écrit :

Ah non c'est un peu plus compliqué, vu qu'une collision peut en cacher une autre :D
Il faut lister les collisions, les trier de façon temporelle, et ne conserver que la première, vu qu'elle va logiquement perturber toutes les suivantes, et tous ces calculs auront été faits pour rien... Mais c'est vrai que j'avais une optique davantage 3D pour ça, où là ça devient un peu plus tendu... en effet pour des billes, ça posera pas vraiment problème.


Vu que tu n'avance que jusqu'à la première collision, tu sais que la suivante est soit :
- la suivante dans la liste triée
- une nouvelle collision issue de la collision tout juste résolue, mais il n'y a que 2 billes (enfin, sauf collision simultanée :D) qui peuvent y participer, seulement 2 billes à tester et pas tout le bordel.
Du coup, les calculs n'ont pas été fait pour rien. la première tournée est en O(n²), comme pour la méthode discrète mais les tours suivants sont en O(n) (+ le maintient de la liste des collisions futures, y'a le choix dans les structures de données, il faut pouvoir éliminer tout les events associés à une bille dès que celle-ci est impliquée dans une collision réalisée, pusher des nouveaux events et poper le plus proche) et on peut continuer comme ça jusqu'à la fin d'un gros pas de temps.
Ça devient seulement problématique si les collisions sont trop rapprochées et que le temps n'avance presque plus (voire pas du tout, à cause d'un manque de précision par exemple), et dans ce cas on peut soit sortir l'artillerie lourde et considérer qu'il faut faire une résolution collision simultanée bien lourdingue, soit simplement sauter un petit pas façon méthode discrète (sauf que le pas est bien plus petit, donc moins de problème de précision, et on fait ça moins souvent que si le pas était tout le temps tout petit), et surtout combiner avec un cutoff pour stopper les billes presques immobiles qui pourraient "vibrer" l'une contre l'autre et faire ramer sans rien produire.


Message édité par 0x90 le 16-03-2010 à 17:21:09

---------------
Me: Django Localization, Yogo Puzzle, Chrome Grapher, C++ Signals, Brainf*ck.
n°1974237
Kenelm
Posté le 16-03-2010 à 17:24:11  profilanswer
 

A un détail près : des collisions peuvent disparaître suite à d'autres collisions... Par conséquent, il est toujours nécessaire de se retaper tous les calculs, et il est plutôt recommandé d'invalider systématiquement tous les calculs précédents pour éviter d'avoir à gérer des collisions fantômes :D

n°1974251
0x90
Posté le 16-03-2010 à 18:34:32  profilanswer
 

Kenelm a écrit :

A un détail près : des collisions peuvent disparaître suite à d'autres collisions... Par conséquent, il est toujours nécessaire de se retaper tous les calculs, et il est plutôt recommandé d'invalider systématiquement tous les calculs précédents pour éviter d'avoir à gérer des collisions fantômes :D


 
Je l'ai marqué dans la parenthèse sur le tas d'events, et il "suffit" de virer les events futurs de collisions de billes impliquées dans les collisions traitées, pas tout les events futurs (et comme au passage on sait que si y'a 2 events futurs sur une bille, le traitement du premier va écarter le second, sauf si le premier event est écarté par le traitement d'un event précédent sur l'autre bille, on peut se permettre de ne stocker dans le tas que le 1er event par bille, et donc alléger les tâches de recherche et de prune, pourvu que la réinclusion dans le set de billes à traiter suite à une collision soit viral même entre billes dont l'event de collision n'est pas premier sur ces billes, et calculer ce set viral c'est pas cher (et plus simple en code que le léger méli-mélo de ma phrase) ).


---------------
Me: Django Localization, Yogo Puzzle, Chrome Grapher, C++ Signals, Brainf*ck.
n°1974266
Kenelm
Posté le 16-03-2010 à 20:18:58  profilanswer
 

Ouais tu l'as marqué après édition :o

mood
Publicité
Posté le 16-03-2010 à 20:18:58  profilanswer
 

n°1974339
alexandre_​j
Posté le 17-03-2010 à 07:23:54  profilanswer
 

Bonjour,
Merci pour toutes ces réponses et cet échange vraiment intéressant !
 
Vu que je débute le projet, je n'ai pas encore beaucoup avancé dans les différentes façon de faire, mais je vais suivre votre conseil. Je vais partir de façon très simlpe avec un petit manager qui testera les collisions entre chaque billes pour débuter, je modifierais au fur et à mesure que les problématiques arriveront :)
 
Merci

n°1974540
0x90
Posté le 17-03-2010 à 13:05:25  profilanswer
 

Kenelm a écrit :

Ouais tu l'as marqué après édition :o


 
Pas faux [:cupra]


---------------
Me: Django Localization, Yogo Puzzle, Chrome Grapher, C++ Signals, Brainf*ck.
n°1977269
alexandre_​j
Posté le 25-03-2010 à 14:08:55  profilanswer
 

Voila, j'ai fini d'implémenter mon système et a part les bugs que vous avez cités, ça fonctionne plutôt bien.
 
Le principal problème finalement, c'est que souvent (tout le temps même au bout d'un moment), mes billes forment des grappes et ne bougent plus. Comme vous l'avez dit, je dois tester mes collisions un brin trop tard. Il est possible également que les paramètres de mes billes ne soit pas adaptés. Une bille possède un vecteur direction (x, y) toujours à 1 ou -1 et une vitesse (= 100). Pour déplacer mes billes je fais ce calcul :
 

Code :
  1. void Ball::move(const float elapsedTime)
  2. {
  3.     //std::cout << "x : " << x_ << "; " << y_ << std::endl;
  4.     float offsetX = direction_.x() * speed_ * elapsedTime;
  5.     float offsetY = direction_.y() * speed_ * elapsedTime;
  6.     x_ += offsetX;
  7.     y_ += offsetY;
  8.     shape_.Move(offsetX, offsetY);
  9. }


 
Ma boucle principale ressemble à ça :

Code :
  1. void GameManager::startGame()
  2. {
  3.     float elapsedTime = 0;
  4.     Clock clock;
  5.     //main loop
  6.     while ( mainWindow_->IsOpened() )
  7.     {
  8.         const Input& input = mainWindow_->GetInput();
  9.        
  10.         //event process
  11.         Event event;
  12.         while ( mainWindow_->GetEvent( event ) )
  13.         {
  14.             //close window
  15.             if ( event.Type == Event::Closed )
  16.                 mainWindow_->Close();
  17.             if ((event.Type == sf::Event::KeyPressed) && (event.Key.Code == sf::Key::A))
  18.                 pause_ = true;
  19.             if ((event.Type == sf::Event::KeyPressed) && (event.Key.Code == sf::Key::Z))
  20.                 pause_ = false;
  21.         }
  22.         //récupération du temps
  23.         elapsedTime = clock.GetElapsedTime();
  24.         clock.Reset();
  25.         if (!pause_)
  26.         {
  27.             //résolution des collisions
  28.             resolveCollisionGameZone();
  29.             //résolution des collisions entre balls
  30.             resolveCollisionBalls();
  31.             //déplacement des balls
  32.             moveBalls(elapsedTime);
  33.         }
  34.         //clear screen
  35.         mainWindow_->Clear();
  36.         //on dessine la zone de jeu
  37.         drawGameZone();
  38.         //on dessine les balls
  39.         drawBalls();
  40.         //draw scene
  41.         mainWindow_->Display();
  42.     }
  43. }


 
Malheureusement, en relisant votre discussion, je ne sais pas vraiment sur quel système partir  :??:

Message cité 1 fois
Message édité par alexandre_j le 25-03-2010 à 14:12:25
n°1977350
0x90
Posté le 25-03-2010 à 16:07:23  profilanswer
 

alexandre_j a écrit :

Voila, j'ai fini d'implémenter mon système et a part les bugs que vous avez cités, ça fonctionne plutôt bien.
 
Le principal problème finalement, c'est que souvent (tout le temps même au bout d'un moment), mes billes forment des grappes et ne bougent plus. Comme vous l'avez dit, je dois tester mes collisions un brin trop tard. Il est possible également que les paramètres de mes billes ne soit pas adaptés. Une bille possède un vecteur direction (x, y) toujours à 1 ou -1 et une vitesse (= 100). Pour déplacer mes billes je fais ce calcul :


Tu parles juste des conditions initiales ou quand tu résouds les collisions tu fais un truc en sorte de garder cette contrainte ? Tu as quoi dans tes fonctions resolveCollision* ?


---------------
Me: Django Localization, Yogo Puzzle, Chrome Grapher, C++ Signals, Brainf*ck.
n°1977355
alexandre_​j
Posté le 25-03-2010 à 16:12:33  profilanswer
 

0x90 a écrit :


Tu parles juste des conditions initiales ou quand tu résouds les collisions tu fais un truc en sorte de garder cette contrainte ? Tu as quoi dans tes fonctions resolveCollision* ?


 
Oui, pour les collisions avec les bordures, j'inverse la direction qui va bien. C'est d'ailleurs peut-être pas la meilleure solution :
 

Code :
  1. /** Gestion des collisions de la zone de jeu */
  2. void GameManager::resolveCollisionGameZone()
  3. {
  4.     int tempY;
  5.     int tempX;
  6.     for (unsigned int i = 0; i < balls_.size(); i++)
  7.     {
  8.         tempX = 0;
  9.         tempY = 0;
  10.         //bordure en Bas
  11.         if ((balls_.at(i)->y() + balls_.at(i)->radius()) > gameZoneRect_.rightBottom().y()) {
  12.             tempY = balls_.at(i)->direction()->y();
  13.             balls_.at(i)->direction()->setY(-1 * tempY);
  14.         }
  15.         //bordure de Droite  
  16.         if ((balls_.at(i)->x() + balls_.at(i)->radius()) > gameZoneRect_.rightBottom().x()) {
  17.             tempX = balls_.at(i)->direction()->x();
  18.             balls_.at(i)->direction()->setX(-1 * tempX);
  19.         }
  20.         //bordure en haut
  21.         if ((balls_.at(i)->y() - balls_.at(i)->radius()) < gameZoneRect_.leftTop().y()) {
  22.             tempY = balls_.at(i)->direction()->y();
  23.             balls_.at(i)->direction()->setY(-1 * tempY);
  24.         }
  25.         //bordure de Gauche
  26.         if ((balls_.at(i)->x() - balls_.at(i)->radius()) < gameZoneRect_.leftTop().x()) {
  27.             tempX = balls_.at(i)->direction()->x();
  28.             balls_.at(i)->direction()->setX(-1 * tempX);
  29.         }
  30.     }
  31. }


 
Et pour ce qui concerne la résolution des collisions entre mes billes, je parcours mes billes :
 

Code :
  1. /** Gestion des collisions entre les balls */
  2. void GameManager::resolveCollisionBalls()
  3. {
  4.     for (unsigned int i = 0; i < balls_.size(); i++)
  5.     {
  6.         for (unsigned int j = (balls_.size() - 1); j > i; j--)
  7.         {
  8.             balls_.at(i)->processCollision(*balls_.at(j));
  9.         }
  10.     }
  11. }


 
Et je calcul mes nouvelles directions. Pour l'instant j'ai bêtement recopié le calcul de cet article : http://fr.wikipedia.org/wiki/Choc_élastique
 

Code :
  1. /** Gestion de la collision avec une autre ball */
  2. void Ball::processCollision(Ball &ball)
  3. {
  4.     if (this->isInCollisionWith(ball))
  5.     {
  6.         // Calcul de la base orthonormée (n,g)
  7.         double nx = (ball.x() - this->x_) / (2 * this->radius_);
  8.         double ny = (ball.y() - this->y_) / (2 * this->radius_);
  9.         double gx = -ny;
  10.         double gy = nx;
  11.         // Calcul des vitesses dans cette base
  12.         double v1n = nx * this->direction_.x() + ny * this->direction_.y();
  13.         double v1g = gx * this->direction_.x() + gy * this->direction_.y();
  14.         double v2n = nx * ball.direction()->x() + ny * ball.direction()->y();
  15.         double v2g = gx * ball.direction()->x() + gy * ball.direction()->y();
  16.         // Permute les coordonnées n et conserve la vitesse tangentielle
  17.         this->direction_.setX( nx * v2n + gx * v1g );
  18.         this->direction_.setY( ny * v2n + gy * v1g );
  19.         ball.direction_.setX( nx * v1n + gx * v2g );
  20.         ball.direction_.setY( ny * v1n + gy * v2g );
  21.     }
  22. }

n°1977363
0x90
Posté le 25-03-2010 à 16:29:41  profilanswer
 

dans ton isInCollisionWith, tu vérifie que les balles s'intersectent seulement ou aussi qu'elles vont bien l'une vers l'autre ?

 

Si tu oublie la seconde condition, des billes qui s'intersectent mais qui sont entrain de se séparer l'une de l'autre, par exemple suite à un choc imparfaitement résolu à la frame d'avant, vont être considérées comme encore en collision, le faux choc va être résolu et va inverser leur direction, elles vont se foncer de nouveau l'une vers l'autre et augmenter leur intersection, il y aura une résolution qui va ensuite les écarter, mais pas assez pour qu'elles cessent de s'intersecter, et le truc va former une grappe petit à petit...

Message cité 1 fois
Message édité par 0x90 le 25-03-2010 à 16:29:50

---------------
Me: Django Localization, Yogo Puzzle, Chrome Grapher, C++ Signals, Brainf*ck.
n°1977424
alexandre_​j
Posté le 25-03-2010 à 17:09:39  profilanswer
 

0x90 a écrit :

dans ton isInCollisionWith, tu vérifie que les balles s'intersectent seulement ou aussi qu'elles vont bien l'une vers l'autre ?
 
Si tu oublie la seconde condition, des billes qui s'intersectent mais qui sont entrain de se séparer l'une de l'autre, par exemple suite à un choc imparfaitement résolu à la frame d'avant, vont être considérées comme encore en collision, le faux choc va être résolu et va inverser leur direction, elles vont se foncer de nouveau l'une vers l'autre et augmenter leur intersection, il y aura une résolution qui va ensuite les écarter, mais pas assez pour qu'elles cessent de s'intersecter, et le truc va former une grappe petit à petit...


 
Exact, je n'avais pas pensé à ce cas de figure. Je vais ajouter comme condition (en plus de savoir si elles sont dans la zone), si les directions sont opposées, comme tu le suggère. Au passage, ma fonction IsInCollisionWith :
 

Code :
  1. bool Ball::isInCollisionWith(const Ball &ball)
  2. {
  3.     //calcul de la distance entre les 2 centres
  4.     double distance = sqrt( ((ball.x() - this->x_) * (ball.x() - this->x_)) + ((ball.y() - this->y_) * (ball.y() - this->y_)) );
  5.     return (distance < (this->radius_ + ball.radius()));
  6. }


 
Au passage, si tu as un avis sur ma façon de coder, ou de structurer la chose, hésites pas, j'essai de progresser en cpp. Bon pour l'instant je suis me suis limité à un GameManger qui gère un peu tout, mais c'est pour passer plus de temps sur le système de collision.
 
Merci en tout cas.

Message cité 1 fois
Message édité par alexandre_j le 25-03-2010 à 17:10:00
n°1977436
0x90
Posté le 25-03-2010 à 17:36:34  profilanswer
 

alexandre_j a écrit :

 

Exact, je n'avais pas pensé à ce cas de figure. Je vais ajouter comme condition (en plus de savoir si elles sont dans la zone), si les directions sont opposées, comme tu le suggère. Au passage, ma fonction IsInCollisionWith :

 
Code :
  1. bool Ball::isInCollisionWith(const Ball &ball)
  2. {
  3.     //calcul de la distance entre les 2 centres
  4.     double distance = sqrt( ((ball.x() - this->x_) * (ball.x() - this->x_)) + ((ball.y() - this->y_) * (ball.y() - this->y_)) );
  5.     return (distance < (this->radius_ + ball.radius()));
  6. }
 

Au passage, si tu as un avis sur ma façon de coder, ou de structurer la chose, hésites pas, j'essai de progresser en cpp. Bon pour l'instant je suis me suis limité à un GameManger qui gère un peu tout, mais c'est pour passer plus de temps sur le système de collision.

 

Merci en tout cas.

 

Tu peux enlever le sqrt et compare la distance au carré de la somme des rayons, l'optimisation c'est pas prioritaire mais cette modification est ultra-courante (les sqrt c'est vachement lourd).

 

Niveau style, bah chacun ses gouts, mais les accesseurs pour x et y ainsi que les "this->" superflus ça alourdit vachement la lecture :/ et dans tes grandes boucles, n'hésite pas à faire un const Ball ball = balls_.at(i) pour alléger. Et les commentaires qui disent exactement la même chose que le nom de la fonction ça sert à rien.

 

Si tu le sens, tu peux tenter de convertir ton code en remplaçant tout les x et y par une "struct point {float x, y; }" avec les opérateurs -, +, -=, +=, =, dotProduct(point b), crossProduct(point b), squaredLength() et length(). Ton code sera nettement plus court (finit les copier/coller de la même ligne pour x et y), et en bonus il suffira presque de rajouter z dans ta structure pour que le code marche aussi en 3D.

Message cité 2 fois
Message édité par 0x90 le 25-03-2010 à 17:37:28

---------------
Me: Django Localization, Yogo Puzzle, Chrome Grapher, C++ Signals, Brainf*ck.
n°1977447
alexandre_​j
Posté le 25-03-2010 à 17:52:08  profilanswer
 

0x90 a écrit :


 
Tu peux enlever le sqrt et compare la distance au carré de la somme des rayons, l'optimisation c'est pas prioritaire mais cette modification est ultra-courante (les sqrt c'est vachement lourd).
 
Niveau style, bah chacun ses gouts, mais les accesseurs pour x et y ainsi que les "this->" superflus ça alourdit vachement la lecture :/ et dans tes grandes boucles, n'hésite pas à faire un const Ball ball = balls_.at(i) pour alléger. Et les commentaires qui disent exactement la même chose que le nom de la fonction ça sert à rien.
 
Si tu le sens, tu peux tenter de convertir ton code en remplaçant tout les x et y par une "struct point {float x, y; }" avec les opérateurs -, +, -=, +=, =, dotProduct(point b), crossProduct(point b), squaredLength() et length(). Ton code sera nettement plus court (finit les copier/coller de la même ligne pour x et y), et en bonus il suffira presque de rajouter z dans ta structure pour que le code marche aussi en 3D.


 
Merci pour les conseils !

n°1977454
bjone
Insert booze to continue
Posté le 25-03-2010 à 17:59:29  profilanswer
 

0x90 a écrit :


 
Tu peux enlever le sqrt et compare la distance au carré de la somme des rayons, l'optimisation c'est pas prioritaire mais cette modification est ultra-courante (les sqrt c'est vachement lourd).
 
Niveau style, bah chacun ses gouts, mais les accesseurs pour x et y ainsi que les "this->" superflus ça alourdit vachement la lecture :/ et dans tes grandes boucles, n'hésite pas à faire un const Ball ball = balls_.at(i) pour alléger. Et les commentaires qui disent exactement la même chose que le nom de la fonction ça sert à rien.
 
Si tu le sens, tu peux tenter de convertir ton code en remplaçant tout les x et y par une "struct point {float x, y; }" avec les opérateurs -, +, -=, +=, =, dotProduct(point b), crossProduct(point b), squaredLength() et length(). Ton code sera nettement plus court (finit les copier/coller de la même ligne pour x et y), et en bonus il suffira presque de rajouter z dans ta structure pour que le code marche aussi en 3D.


 
const Ball &ball = balls_.at(i) plustôt ?

n°1977465
0x90
Posté le 25-03-2010 à 18:15:49  profilanswer
 

bjone a écrit :

 

const Ball &ball = balls_.at(i) plustôt ?


Pas forcément, si le compilo est stupide et que Ball est gros, copier un Ball entier pour n'en lire que des bouts serait effectivement une perte de temps, sauf que le compilo est pas complètement stupide dans ce cas, s'il utilise pas un membre de Ball, il ne le copiera pas dans la stack pour rien, il ne prendra que les bouts utiles, exactement comme quand tu fais un "const Ball&" et que quand tu lis un membre il le copie.
Par contre, si dans ton scope en cours tu as un Ball& ou un Ball* qui traine, que tu fais des écritures dessus, il est possible que ça invalide les données lues par ton const Ball& (peut-être que c'est pas vraiment possible, mais que le compilo arrive pas à le déduire), par exemple (un cas super-pathologique):

Code :
  1. for (int i=1; i<balls_.size(); ++i) {
  2.  Ball& foo = balls_.at(i);
  3.  for (int j=0; j<i; ++j) {
  4.    const Ball& bar = balls_.at(j);
  5.    foo.x += bar.x;
  6.    foo.x += bar.x;
  7.  }
  8. }


Imaginons que le compilo n'arrive pas à comprendre que puisque j est toujours inférieur à i, alors foo et bar ne peuvent pas pointer sur le même objet. alors le compilo est obligé de se dire que peut-être que quand on modifie foo, on modifie bar aussi, donc après le premier "foo.x += bar.x;" peut-être que bar.x a changé, donc qu'il faut aller le relire en mémoire pour faire le second +=. Si t'avais simplement eu un "Ball bar", il saurait que les données de bar sont inacessible via la référence foo et éviterait de recharger la valeur de bar.x une seconde fois. Et comme le compilo élimine les load inutile, il n'aurait copié que Ball.x dans la stack (sauf si le constructeur par copie de Ball est non-trivial).


Message édité par 0x90 le 25-03-2010 à 18:17:34

---------------
Me: Django Localization, Yogo Puzzle, Chrome Grapher, C++ Signals, Brainf*ck.
mood
Publicité
Posté le   profilanswer
 


Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  Algo

  Système de collision

 

Sujets relatifs
Système de cache PHP et charge CPUSysteme d'achat de crédit
collision de sprites : quelle direction donner après collision[résolu]Systeme de cache et nombre de fichiers
[PHP] Système de chargement de ma pageDefinition d'un système linguistique.
système manuel de programmation neurologique à refllex par Rdn formelscherche fonction qui indique les performances du système
cherche systeme de ""carte de fidelité"Développement d'un système de rendez vous automatique
Plus de sujets relatifs à : Système de collision


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR