IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Physique Discussion :

Détection de collisions pixel perfect en 2D


Sujet :

Physique

  1. #1
    Rédacteur
    Avatar de Bakura
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    1 386
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 386
    Points : 2 640
    Points
    2 640
    Par défaut
    Bonjour à tous,

    J'ai essayé moi aussi de me plonger dans un petit test de cette technique que vous appelez Pixel Perfect, mais je bloque un peu.

    Je commence peut-être dans une direction tout à fait mauvaise, mais pour l'instant, je fais sur chaque sprite un vector bidimensionnel, puis dans chaque constructeur de la classe Sprite :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // Initialisation du tableau de booléen
       HDC hDC = GetDC (NULL);
     
       m_bEtatsPixels.resize (500);
     
       for (int x = 0 ; x <= LireLargeur() ; x++)
          for (int y = 0 ; y <= LireHauteur() ; y++)
          {
             if (GetPixel (hDC, x, y) == RGB (255, 255, 0)) // Si le pixel est transparent, true
                m_bEtatsPixels [x][y] = true;
     
             else
                m_bEtatsPixels [x][y] = false; // Le pixel est visible, false
          }
    Je crois que je vais inverser le true et le false, ça me parait pas logique comme ça . Par contre j'ai un peu oublié comment fonctionnait exactement les vector, et je suis obligé de faire un resize sinon ça marche pas, et en faisant un push_back ça ne fonctionne pas, mais bon c'est pas très grave.

    Donc ça en gros si j'ai bien compris c'est ce qu'il faut faire ? Etatn donné que ma couleur de transparence est le magenta, je parcours chaque pixel pour vérifier son état.

    Mais après je bloque. Voici ma fonction Test Collision :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    bool Sprite::TestCollision (Sprite * pSprite)
    {
       // On récupère le rectangle de collision du deuxième sprite
       RECT & rcCollisionFrappe = pSprite->LireRectCollision ();
     
       /*if (m_rcCollision.left <= rcCollisionFrappe.right &&
           rcCollisionFrappe.left <= m_rcCollision.right &&
           m_rcCollision.top <= rcCollisionFrappe.bottom &&
           rcCollisionFrappe.top <= m_rcCollision.bottom)
          return true;*/
     
       // Si true, les rectangles de collision se chevauchent
       if (m_rcCollision.left <= rcCollisionFrappe.right &&
           rcCollisionFrappe.left <= m_rcCollision.right &&
           m_rcCollision.top <= rcCollisionFrappe.bottom &&
           rcCollisionFrappe.top <= m_rcCollision.bottom)
       {
          // True, donc on récupère le rectangle on s'est produit la collision
          RECT rcCollision;
          rcCollision.left =
     
          vector < vector <bool> > bEtatsPixels = pSprite->LireEtatsPixels();
     
     
       }
     
       else
          return false;
    }
    C'est un peu le bordel désolé, je suis en train de faire des tests donc ya des commentaires un peu partout lol.

    Bon donc en gros avant avec les collisions via les "boudings box" (enfin les boîtes ^^), ça marchait sans problème. La en fait ce que je voudrais trouvé c'est le petit rectangle de collision, et après c'est simple il suffit de tester tous les pixels et si il y en a deux qui sont false il y a collision, mais je n'arrive pas à trouver comment calculer ce "rectangle" de collision. Quelqu'un pour m'aider ?

  2. #2
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    m_bEtatsPixels.resize (500);
    Là tu ne dimensionnes que la première dimension de ton tableau, pas la seconde. Il faut également faire un resize sur chaque élément de m_bEtatsPixels (éléments qui sont des vector, donc).

    mais je n'arrive pas à trouver comment calculer ce "rectangle" de collision
    Il faut prendre le maximum des Left (respectivement Top) de chaque rectangle comme Left (respectivement Top) du rectangle de collision, et inversement il faut prendre le minimum des Right (respectivement Bottom) de chaque rectangle comme Right (respectivement Bottom), du rectangle de collision. Si Left > Right ou si Top > Bottom, il n'y a pas collision. Sinon, tu as ton rectangle de collision.

  3. #3
    Rédacteur
    Avatar de Bakura
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    1 386
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 386
    Points : 2 640
    Points
    2 640
    Par défaut
    Merci pour ta réponse. Dans tous les cas, ça a l'air quand même moins dur que je le pensais (dixit le livre que c'était une technique pour programmeur avancé :/), j'avais un peu peur de me lancer là dedans, mais ça va ^^.

    Bon alors comme ce que tu m'as dit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    // Initialisation du tableau de booléen
       HDC hDC = GetDC (NULL);
     
       m_bEtatsPixels.resize (500);
     
       for (int x = 0 ; x <= LireLargeur() ; x++)
       {
          m_bEtatsPixels [x].resize (500);
          for (int y = 0 ; y <= LireHauteur() ; y++)
          {
             if (GetPixel (hDC, x, y) == RGB (255, 0, 255)) // Si le pixel est transparent, false
                m_bEtatsPixels [x][y] = false;
     
             else
                m_bEtatsPixels [x][y] = true; // Le pixel est visible, true
          }
       }
    J'alloue 500 colonnes pour chaque ligne, c'est bien ce que cela fait ?

    Je m'étais gouré de couleur sur le code au dessus, c'est du magenta donc 255, 0, 255 ^^. Donc si le pixel est transparent (magenta), il sera réglé sur false, sinon il sera visible donc sur true. Jusque là ça va.

    Puis voici la fonction TestCollision :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    // Définition de la fonction TestCollision
    bool Sprite::TestCollision (Sprite * pSprite)
    {
       // On récupère le rectangle de collision du deuxième sprite
       RECT & rcCollisionFrappe = pSprite->LireRectCollision ();
     
       // Si true, les rectangles de collision se chevauchent
       if (m_rcCollision.left <= rcCollisionFrappe.right &&
           rcCollisionFrappe.left <= m_rcCollision.right &&
           m_rcCollision.top <= rcCollisionFrappe.bottom &&
           rcCollisionFrappe.top <= m_rcCollision.bottom)
       {
          // True, donc on récupère le rectangle on s'est produit la collision
          RECT rcCollision;
     
          (m_rcCollision.left < rcCollisionFrappe.left ? rcCollision.left = rcCollisionFrappe.left :
          rcCollision.left = m_rcCollision.left);
          (m_rcCollision.right < rcCollisionFrappe.right ? rcCollision.right = m_rcCollision.right :
          rcCollision.right = rcCollisionFrappe.right);
          (m_rcCollision.top > rcCollisionFrappe.top ? rcCollision.top = m_rcCollision.top :
          rcCollision.top = rcCollisionFrappe.top);
          (m_rcCollision.bottom > rcCollisionFrappe.bottom ?
          rcCollision.bottom = rcCollisionFrappe.bottom : rcCollision.bottom = m_rcCollision.bottom);
     
          vector < vector <bool> > bEtatsPixels = pSprite->LireEtatsPixels();
     
          // On boucle dans le rectangle de collision. Si deux pixels visibles se chevauchent, alors
          // il y a collision, sinon on retourne false
          for (int x = rcCollision.left ; x <= rcCollision.right ; x++)
             for (int y = rcCollision.top ; y <= rcCollision.bottom ; y++)
             {
                if ((bEtatsPixels [x][y] == true) && (m_bEtatsPixels [x][y] == true))
                   return true;
             }
     
          return false;
       }
     
       else
          return false;
    }
    Il y a certainement plein de calculs inutiles, mais bon s'pa grave, pour le moment je veux juste que ça marche ^^. Donc grâce à ce que tu m'as dit, je peux maintenant récupérer le rectangle de collision, et donc après à travers la boucle je vérifie chaque pixel un à un, ceux du premier et du second sprite, et si les deux sont réglés sur true (donc visible), il y a collision, sinon il n'y a pas collision.

    Mais ça ne marche pas, il détecte les collisions comme avant, avec le gros rectangle de collision et pas au pixel près...

    D'après moi, l'erreur se situe au niveau des constructeurs, pour récupérer la couleur et régler le vector sur bool ou false, mais je suis pas sur.

  4. #4
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    J'alloue 500 colonnes pour chaque ligne, c'est bien ce que cela fait ?
    Oui. Par contre, pourquoi 500x500 et non LireLargeur()xLireHauteur() ?

    D'après moi, l'erreur se situe au niveau des constructeurs, pour récupérer la couleur et régler le vector sur bool ou false, mais je suis pas sur
    Pour en avoir le coeur net, suffit d'afficher ton tableau dans un fichier texte sous forme de 0 et de 1 par exemple. Tu verras tout de suite si tu retrouves la forme de ton sprite ou non.

    Il y a tout de même un truc qui me paraît louche : je ne vois pas comment un "GetDC(NULL)" pourrait te renvoyer un HDC sur une quelconque surface que tu as chargé toi-même. D'ailleurs tu devrais tester le HDC renvoyer, c'est un minimum.

    Mais ça ne marche pas, il détecte les collisions comme avant, avec le gros rectangle de collision et pas au pixel près...
    Une erreur déjà : lorsque tu testes les pixels, il faut appliquer un décalage. En effet le pixel (0, 0) de ton rectangle de collision ne sera pas forcément le pixel (0, 0) des deux rectangles originaux.

    Autre erreur : tu prends le maximum sur left / right et le minimum sur top / bottom, ce devrait être le maximum sur left / top et le minimum right / bottom.

  5. #5
    Rédacteur
    Avatar de Bakura
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    1 386
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 386
    Points : 2 640
    Points
    2 640
    Par défaut
    Oui. Par contre, pourquoi 500x500 et non LireLargeur()xLireHauteur() ?
    Ca c'est corrigé ^^. Je l'avais pas fait parceque ça ne marchait pas avant, mais là, c'est bon.

    Pour en avoir le coeur net, suffit d'afficher ton tableau dans un fichier texte sous forme de 0 et de 1 par exemple. Tu verras tout de suite si tu retrouves la forme de ton sprite ou non.

    Il y a tout de même un truc qui me paraît louche : je ne vois pas comment un "GetDC(NULL)" pourrait te renvoyer un HDC sur une quelconque surface que tu as chargé toi-même. D'ailleurs tu devrais tester le HDC renvoyer, c'est un minimum.
    C'est ce que j'ai fait, et en effet, le problème est bien là. Quelque soit l'image (j'ai essayé avec deux images de même dimensions mais pas avec le même motif a l'intérieur), j'obtient ceci :

    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    01100100000000001100100100000000110110000000000000000000000
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111
    11111111111111111111111111111111111111111111111111111111111


    Bref très loin des dessins.

    Pour le GetDC (NULL), je l'ai changé. J'ai passé à chacun de mes constructeurs l'handle de fenêtre, donc ça fait GetDC (hWindow). J'ai testé la valeur de retour visiblement ça marche bien.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Autre erreur : tu prends le maximum sur left / right et le minimum sur top / bottom, ce devrait être le maximum sur left / top et le minimum right / bottom.
    Merci, corriger aussi ^^...

    Mais là plus je suis en train de regarder le code, plus la ligne : if (GetPixel (hDC, x, y) == RGB (255, 0, 255)) me parait bizarre. Parceque je ne vois pas ce qu'il peut chercher comme pixel vu que dans le constructeur le bitmap n'est pas dessiné !

    Disolé d'avoir tant de mal...

  6. #6
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    Ok, je crois que le problème se situe plus haut

    Comment charges tu tes images ? Sous quelle forme ? Tu utilises quelle bibliothèque 2D ?

  7. #7
    Rédacteur
    Avatar de Bakura
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    1 386
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 386
    Points : 2 640
    Points
    2 640
    Par défaut
    Ah oui désolé j'avais pas vu que c'était un forum SDL ^^. J'utilise l'api Windows, et je charge mes bitmaps avec la fonction LoadImage(), et ça fonctionne très bien ^^.

    Mais là c'est vrai que je me demande comment la fonction GetPixel peut fonctionner vu que je ne les dessine pas les bitmaps dans le constructeur.

    Allez, j'y suis presque j'en suis sûr ^^.

  8. #8
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    Mais là c'est vrai que je me demande comment la fonction GetPixel peut fonctionner vu que je ne les dessine pas les bitmaps dans le constructeur
    Le HDC que tu donnes à manger à GetPixel doit correspondre à l'image que tu veux tester (pas besoin de l'avoir dessinée, elle est de toute façon quelque part en mémoire après l'appel à LoadImage).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    // Tu charges ton image
    HANDLE Bitmap = LoadImage(...);
     
    // Tu crées un DC dans lequel tu vas pouvoir accéder aux pixels de ton image
    HDC Hdc = CreateCompatibleDC(NULL);
    SelectObject(Hdc, Bitmap);
     
    ...
     
    // Ton GetPixel devrait fonctionner
    GetPixel(Hdc, x, y);
     
    ...
     
    // N'oublie pas de libérer le DC avant de quitter la fonction
    ReleaseDC(Hdc);

  9. #9
    Rédacteur
    Avatar de Bakura
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    1 386
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 386
    Points : 2 640
    Points
    2 640
    Par défaut
    Euh... ça ne marche pas. Voici ce que je fais :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    HBITMAP hBitmap = m_pBitmap->LireBitmap();
       HDC hDC = CreateCompatibleDC (NULL);
       SelectObject(hDC, hBitmap);
     
       m_bEtatsPixels.resize (LireLargeur());
     
       for (int x = 0 ; x <= LireLargeur() ; x++)
       {
          m_bEtatsPixels [x].resize (LireHauteur());
          for (int y = 0 ; y <= LireHauteur() ; y++)
          {
             if (GetPixel (hDC, x, y) == RGB (255, 0, 255)) // Si le pixel est transparent, false
                m_bEtatsPixels [x][y] = false;
     
             else
                m_bEtatsPixels [x][y] = true; // Le pixel est visible, true
          }
       }
     
       ofstream sortieFichierClient ("clients.txt", ios::out);
     
       for (int x = 0 ; x <= LireLargeur() ; x++)
       {
          for (int y = 0 ; y <= LireHauteur() ; y++)
          {
             sortieFichierClient << m_bEtatsPixels [x][y];
          }
          sortieFichierClient << endl;
       }
     
       ReleaseDC (hWindow, hDC);
    En fait le bitmap est déjà chargé dans la classe Bitmap. Donc ce que je fais pour récupérer le HBITMAP ben j'ai créé une fonction qui renvoie le HBITMAP. Et après je fais comme tu dis mais ça ne marche pas mieux, toujours le même résultat dans le fichier txt. Pire, les sprites ne s'affichent même plus... Si tu veux le code complet (en fichier rar), dit le moi ^^.

  10. #10
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    Je pense que tu devrais clôre ce sujet, et aller poser ta question purement Win32 sur le forum "Développement Windows"

    Une fois la lecture des pixels correctement réalisée, si tu as de nouveau des problèmes avec les collisions, tu pourras revenir sur ce sujet.

  11. #11
    Rédacteur
    Avatar de Bakura
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    1 386
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 386
    Points : 2 640
    Points
    2 640
    Par défaut
    Compris ^^...

  12. #12
    Rédacteur
    Avatar de Bakura
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    1 386
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 386
    Points : 2 640
    Points
    2 640
    Par défaut
    Comme tu dois t'en douter, je reviens parceque j'ai de nouveau un problème ^^.

    Pour le problème des booléens, j'ai régler ça tout seul. Donc maintenant dans mon fichier de test j'ai bien des 1 là ou l'image s'affiche et des 0 sur les surfaces transparentes. J'ai testé avec une image complexe et un carré et ça marche parfait ^^...

    Mais là après deux heures de triturage d'esprit je bloque sur le décalage que tu m'avais fait remarquer, et pourtant j'ai vérifier sur des feuilles de papier et d'après moi ça m'a l'air bon, mais ça n'a pas l'air de fonctionner, je suis sûrement sur la mauvaise voie.

    Voici le code de ma fonction TestCollision, encore une fois il y a surement des calculs superficiels mais pour l'instant je veux surtout que ça marche :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    // Définition de la fonction TestCollision
    bool Sprite::TestCollision (Sprite * pSprite)
    {
       // On récupère le rectangle de collision du deuxième sprite
       RECT & rcCollisionFrappe = pSprite->LireRectCollision ();
     
       // Si true, les rectangles de collision se chevauchent
       if (m_rcCollision.left <= rcCollisionFrappe.right &&
           rcCollisionFrappe.left <= m_rcCollision.right &&
           m_rcCollision.top <= rcCollisionFrappe.bottom &&
           rcCollisionFrappe.top <= m_rcCollision.bottom)
       {
          // True, donc on récupère le rectangle on s'est produit la collision
          RECT rcCollision;
          int iPointXA, iPointXB, iPointYA, iPointYB;
     
          (m_rcCollision.left < rcCollisionFrappe.left ? rcCollision.left = rcCollisionFrappe.left,
           iPointXA = rcCollision.left - m_rcCollision.left, iPointYA = rcCollision.top -
           m_rcCollision.top, iPointXB = 0, iPointYB = rcCollision.top - rcCollisionFrappe.top :
           rcCollision.left = m_rcCollision.left, iPointXA = 0, iPointYA = rcCollision.top -
           m_rcCollision.top, iPointXB = rcCollision.left - rcCollisionFrappe.left,
           iPointYB = rcCollision.top - rcCollisionFrappe.top);
          (m_rcCollision.right < rcCollisionFrappe.right ? rcCollision.right = m_rcCollision.right :
           rcCollision.right = rcCollisionFrappe.right);
          (m_rcCollision.top < rcCollisionFrappe.top ? rcCollision.top = m_rcCollision.top :
           rcCollision.top = rcCollisionFrappe.top);
          (m_rcCollision.bottom < rcCollisionFrappe.bottom ? rcCollision.bottom = m_rcCollision.bottom :
           rcCollision.bottom = rcCollisionFrappe.bottom);
     
          vector < vector <bool> > bEtatsPixels = pSprite->LireEtatsPixels();
     
          // On boucle dans le rectangle de collision. Si deux pixels visibles se chevauchent, alors
          // il y a collision, sinon on retourne false
          for (int x = rcCollision.left ; x <= rcCollision.right ; x++, iPointXA++, iPointXB++)
             for (int y = rcCollision.top ; y <= rcCollision.bottom ; y++, iPointYA++, iPointYB++)
             {
                if ((m_bEtatsPixels [iPointXA][iPointYA] == true) &&
                    (bEtatsPixels [iPointXB][iPointYB] == true))
                   return true;
             }
       }
     
       return false; // Pas de collision
    }
    Comme avant je récupère le rectangle de collision du sprite avec lequel je vais le comparer (en fait, ce rectangle de collision ne sert plus à grand chose. Sur l'ancienne version de mes collisions, c'était un rectangle diminuer d'un douzième par rapport à la taille initiale du sprite, pour faire des collisions un peu mieux, mais étant donné que avec le pixel perfect ya plus besoin, j'ai supprimer le rétrecissement d'un douzième donc le rectangle de collision est le même que celui de position).

    Puis je vérifie si les deux sprites se sont chevauchés, et je récupère les coordonnés de ce rectangle. Puis ensuite j'ai quatre entiers iEntierXA, iEntierYA, iEntierXB et iEntierYB. Les deux A sont pour le premier sprite et les deux B pour le deuxième sprite. Et normalement je fais quelques petits calculs simples sur le premier opérateur ternaire de manière à ce que iEntierXA et iEntierYA soient les coordonnés par rapport au vector (comme tu l'avais fait remarqué au début je règle les bools avec l'image à 0;0 mais vu qu'elle bouge il faut le décalage), pareil pour l'autre sprite.

    Puis après dans les for j'ai plus qu'à faire les comparaisons et normalement ça devrait marcher mais... ça marche pas ^^... Le programme plante quand les deux sprites rentrent en collision.

    S'il te plait me donne pas de réponse, dit moi plutôt ou je me trompe ^^, j'aimerais bien réussir tout seul ^^

  13. #13
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    Première chose : je remplacerais ces opérateurs ternaires à rallonge par des vrais if. Ca ne changera peut-être pas grand chose, mais au moins le code sera plus clair pour tout le monde, et ça évitera peut-être des erreurs de syntaxe idiotes qu'on n'aurait pas vues.

    Ensuite, si ça plante, peut-être est-ce dû à un dépassement sur les indices de tes tableaux ? Commence par vérifier ça. Vérifie aussi avec deux rectangles de test si les décalages sont bien calculés.

    Moi je pense que non : tu calcules les décalages sur Top dans le test de Left

  14. #14
    Rédacteur
    Avatar de Bakura
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    1 386
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 386
    Points : 2 640
    Points
    2 640
    Par défaut
    Désolé de te déranger de nouveau, mais là, j'y suis presque de chez presque ^^...

    Donc voici mon dernier code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
     
    bool Sprite::TestCollision (Sprite * pSprite)
    {
       // On récupère le rectangle de collision du deuxième sprite
       RECT & rcCollisionFrappe = pSprite->LireRectCollision ();
     
       // Si true, les rectangles de collision se chevauchent
       if (m_rcCollision.left <= rcCollisionFrappe.right &&
           rcCollisionFrappe.left <= m_rcCollision.right &&
           m_rcCollision.top <= rcCollisionFrappe.bottom &&
           rcCollisionFrappe.top <= m_rcCollision.bottom)
       {
          // True, donc on récupère le rectangle on s'est produit la collision, puis on calcul les
          // décalages
          RECT rcCollision;
          int iPointXA, iPointXB, iPointYA, iPointYB;
     
          // Gauche
          if (m_rcCollision.left < rcCollisionFrappe.left)
          {
             rcCollision.left = rcCollisionFrappe.left;
             iPointXA = rcCollision.left - m_rcCollision.left;
             iPointXB = 0;
          }
     
          else
          {
             rcCollision.left = m_rcCollision.left;
             iPointXA = 0;
             iPointXB = rcCollision.left - rcCollisionFrappe.left;
          }
     
          // Droite
          (m_rcCollision.right < rcCollisionFrappe.right ? rcCollision.right = m_rcCollision.right :
           rcCollision.right = rcCollisionFrappe.right);
     
          // Haut
          if (m_rcCollision.top < rcCollisionFrappe.top)
          {
             rcCollision.top = m_rcCollision.top;
             iPointYA = rcCollision.top - m_rcCollision.top;
             iPointYB = rcCollision.top - rcCollisionFrappe.top;
          }
     
          else
          {
             rcCollision.top = rcCollisionFrappe.top;
             iPointYA = rcCollision.top - m_rcCollision.top;
             iPointYB = rcCollision.top - rcCollisionFrappe.top;
          }
     
          // Bas
          (m_rcCollision.bottom < rcCollisionFrappe.bottom ? rcCollision.bottom = m_rcCollision.bottom :
           rcCollision.bottom = rcCollisionFrappe.bottom);
     
          vector < vector <bool> > bEtatsPixels = pSprite->LireEtatsPixels();
     
          // On boucle dans le rectangle de collision. Si deux pixels visibles se chevauchent, alors
          // il y a collision, sinon on retourne false
     
          int iInitialA = iPointYA;
          int iInitialB = iPointYB;
     
          for (int x = rcCollision.left ; x <= rcCollision.right ; x++, iPointXA++, iPointXB++)
          {
             for (int y = rcCollision.top ; y <= rcCollision.bottom ; y++, iPointYA++, iPointYB++)
             {
                if ((m_bEtatsPixels [iPointXA][iPointYA] == true) &&
                    (bEtatsPixels [iPointXB][iPointYB] == true))
                   return true;
             }
     
             iPointYA = iInitialA;      // On rétablie les décalages Y initiaux
             iPointYB = iInitialB;
          }
       }
     
       return false; // Pas de collision
    }
    Comme tu m'as dit, j'ai mis pour le left et top dans des if/else, c'est en effet beaucoup plus clair. J'ai corrigé également le coup des comparaisons avec les top dans les left, je suis vraiment trop bête ^^. J'ai revérifié tous mes calculs sur une feuille, ils sont bons, normalement... J'ai fait des schémas sur toutes les possibilités possibles (il y a en 4 normalement, le sprite 1 a gauche du sprite 2 soit avec un top inférieur au sprite 2 ou soit un top supérieur au sprite 2, et le sprite 1 à droite du sprite 2 soit avec un top inférieur au sprite 2 ou soit avec un top supérieur au sprite 2)...

    Au niveau du for, il y avait effectivement une erreur de dépassement. Au niveau du deuxième for j'incrémentais à chaque fois les iPointYA et iPointYB. Lors de la première passe de la première boucle ça passait, mais après lors de la deuxième passe hop ça dépassait, j'ai donc corrigé le problème avec les deux nouvelles variables.

    J'ai également vérifié que ma fonction LireEtatsPixels() retourne bien le bon vector, j'ai vérifié avec un fichier, et c'est le bon, donc jusqu'ici tout est bon.

    Mais quand je fais le test, ils réagissent bien (plus d'erreur d'execution) mais toujours avec leurs boîtes de collisions. Mais ce qui est le plus étrange, c'est que quand je prend le contrôle d'un sprite avec le clavier et que je "rentre" dans la boîte de collision et que je me rapproche du deuxième sprite, il me détecte pas de collision et il faut que je rentre dedans au pixel près pour que la collision soit détecté, ce qui signifie que ça marche pas :/. C'est assez bizarre... Si tu as besoin d'un fichier exe pour voir ça, pas de problème

  15. #15
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    Est-ce que tu as vérifié les coordonnées de ton rectangle de collision ? Tu as essayé d'écrire dans un fichier les zones correspondantes dans les deux sprites ?

  16. #16
    Rédacteur
    Avatar de Bakura
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    1 386
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 386
    Points : 2 640
    Points
    2 640
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Est-ce que tu as vérifié les coordonnées de ton rectangle de collision ? Tu as essayé d'écrire dans un fichier les zones correspondantes dans les deux sprites ?
    Je ne comprends pas très bien,... Mais sinon, je pense que le problème se situe autre part, car j'ai ajouté ce petit code dans la boucle :

    sortieFichierClient << m_bEtatsPixels [iPointXA][iPointYA] << " ";
    sortieFichierClient << bEtatsPixels [iPointXB][iPointYB] << endl;

    Et a aucun moment dans le fichier j'ai deux 1, soit 0 1 ou 1 0, donc je vois pas pourquoi il fait une collision,...

    EDIT : hum, j'ai un truc bizarre quand j'écris :

    sortieFichierClient << rcCollision.left << ' ' << rcCollision.right << ' ' <<
    rcCollision.top << ' ' << rcCollision.bottom;
    sortieFichierClient << endl << iPointXA << ' ' << iPointYA << ' ' << iPointXB << ' ' << iPointYB;

    j'obtiens dans le fichier

    79 80 268 326
    0 0 57 -28

    Le -28 est bizarre...

  17. #17
    Membre régulier
    Inscrit en
    Novembre 2002
    Messages
    291
    Détails du profil
    Informations forums :
    Inscription : Novembre 2002
    Messages : 291
    Points : 81
    Points
    81
    Par défaut
    Salut, je m'incruste dans ce sujet car en fait j'essaye egalement de faire un ptit pixel perfect et j'ai aussi un petit prob

    Mon objet a en fait "2" hauteurs/largeurs : une hauteur à l'ecran et une hauteur de la texture.

    Donc ma premiere etape consiste a detecter le rectangle de collision de mon objet à l'ecran (ca ok facile)
    (
    d'ailleur petite parenthese : pour l'avoir n'est ce pas plus simple de faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    int OrigineX = max(m_Position.x, Rect.GetPosition().x);
    int OrigineY = max(m_Position.y, Rect.GetPosition().y);
    int ExtX     = min(m_Position.x + m_Taille.x, Rect.GetPosition().x + Rect.GetTaille().x);
    int ExtY     = min(m_Position.y + m_Taille.y, Rect.GetPosition().y + Rect.GetTaille().y);
    texter si (OrigineX < ExtX) && (OrigineY < ExtY)
    puis apres renvoyer Rectangle(OrigineX, OrigineY, ExtX, ExtY) si vrai
    )

    .... mais ensuite, pour faire la detection des pixels, je ne peux pas utiliser ce rectangle tel quel...

    il faudrait que je puisse "convertir" mon rectangle de collision (à l'ecran) en rectangle de collision réel de la texture... mais là je seche... !!!
    (ma premiere idée serai de multiplier la hauteur de ce rectangle par le rapport HauteurReel/HauteurEcran... mais je risque d'avoir des pertes ? dans le sens ou à un moment je ferai un arrondi qqpart...)

  18. #18
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    Le -28 est bizarre...
    Compare ton calcul pour les X et ton calcul pour les Y : ce ne sont déjà pas les mêmes. Tu devrais trouver le problème tout seul

    ma premiere idée serai de multiplier la hauteur de ce rectangle par le rapport HauteurReel/HauteurEcran... mais je risque d'avoir des pertes ? dans le sens ou à un moment je ferai un arrondi qqpart...
    Je ne vois pas comment faire autrement. De toute façon si tu fais le va-et-vient entre deux tailles différentes, forcément tu auras une perte à un moment ou un autre.

  19. #19
    Rédacteur
    Avatar de Bakura
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    1 386
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 386
    Points : 2 640
    Points
    2 640
    Par défaut
    En effet, attention cette fois-ci ca m'a trop saoulé alors j'ai sorti mon papier millimitré et j'ai tout bien fait . Cette fois-ci, plus aucun doute, voici les bons calculs :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    // Gauche
          if (m_rcCollision.left < rcCollisionFrappe.left)
          {
             rcCollision.left = rcCollisionFrappe.left;
             iPointXA = rcCollision.left - m_rcCollision.left;
             iPointXB = 0;
          }
     
          else
          {
             rcCollision.left = m_rcCollision.left;
             iPointXA = 0;
             iPointXB = rcCollision.left - rcCollisionFrappe.left;
          }
     
          // Haut
          if (m_rcCollision.top < rcCollisionFrappe.top)
          {
             rcCollision.top = rcCollisionFrappe.top;
             iPointYA = rcCollision.top - m_rcCollision.top;
             iPointYB = 0;
          }
     
          else
          {
             rcCollision.top = m_rcCollision.top;
             iPointYA = 0;
             iPointYB = rcCollision.top - rcCollisionFrappe.top;
          }
    Mais ça ne marche toujours pas ^^. Je vais essayer de remonter un peu plus haut dans le programme voir si ça merde pas ailleurs...

  20. #20
    Membre régulier
    Inscrit en
    Novembre 2002
    Messages
    291
    Détails du profil
    Informations forums :
    Inscription : Novembre 2002
    Messages : 291
    Points : 81
    Points
    81
    Par défaut
    ok alors pas d'autres choix que la division... mais autre souci...

    du coup, le rectangle de collision ne coincide plus....

    dois je faire ca ? :
    1. Calculer le premier rectangle de collision
    2. Transformer pour chq objet ce rectangle en rectangle reel (avec leur rapport dimensionReelle/domensionEcran respectif)
      (rect0 = Rectangle(rect.Position(), rect.Taille() * rapport0) (pareil pour l'autre)
    3. Refaire un teste de collision des 2 rectangles reel pour avoir le vrai rectangle de collision(celui des texture)


    merci

Discussions similaires

  1. Théorie des collisions : collision au pixel près (pixel perfect)
    Par LittleWhite dans le forum Développement 2D, 3D et Jeux
    Réponses: 7
    Dernier message: 19/12/2013, 11h16
  2. [moteur 2D][c++]Pixel perfect collision
    Par nikau6 dans le forum Développement 2D, 3D et Jeux
    Réponses: 7
    Dernier message: 19/02/2009, 15h48
  3. 2D - Pixel Perfect Collision
    Par Zacks dans le forum DirectX
    Réponses: 2
    Dernier message: 21/05/2006, 03h10
  4. [2D] Faiblesse de l'algo de collision pixel-perfect
    Par CPPTryer dans le forum Physique
    Réponses: 3
    Dernier message: 28/03/2006, 18h45

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo