Partage
  • Partager sur Facebook
  • Partager sur Twitter

AABB bloqué sur les coins

Sujet résolu
Anonyme
    29 mai 2021 à 20:08:41

    Bonjour, bonsoir. Même après beaucoup de recherches et d'essais, je me retrouve confronté à un problème :

    Je crée un jeu depuis 2 mois mais j'ai toujours des problèmes au niveau des collisions... J'ai utilisé la technique AABB mais je suis bloqué au bord voire à l'intérieur du modèle en touchant un bord.

    Voici mon code :

    if (translation.x + collision.x <= entity->translation.x + width
    && translation.x + width >= entity->translation.x
    && translation.y <= entity->translation.y + height
    && translation.y + height >= entity->translation.y
    && translation.z <= entity->translation.z + depth
    && translation.z + depth >= entity->translation.z)
    {
    translation.x = entity->translation.x + (translation.x > entity->translation.x ? width : -width);
    collision.x *= -1;
    }


    collision.x sert à "prévoir" la collision. S'il n'était pas là, il y aura une collision, le joueur déjà dans l'objet, donc c'est un peu inutile :p. Ce calcul est pour l'axe X, mais j'en fait un similaire pour les autres axes.


    Par contre, je n'arrive pas à sauter des lignes dans mon code...

    -
    Edité par Anonyme 29 mai 2021 à 20:12:12

    • Partager sur Facebook
    • Partager sur Twitter
      30 mai 2021 à 23:49:08

      le code est illisible.
      • Partager sur Facebook
      • Partager sur Twitter
      Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
        31 mai 2021 à 2:45:36

        Salut,

        Qu'est ce que des translations, collisions, entités viennent foutre dans une détection de collision ?

        Basiquement, pour chaque entité, tu définit une boite englobante.
        La détection de collision vérifie juste si 2 boites s'entrecroisent.

        Quand à faire du prédictif, tu dois d'abord calculer la prochaine position des entités, et ensuite faire le test de collision.

        • Partager sur Facebook
        • Partager sur Twitter
          31 mai 2021 à 8:28:19

          Salut,

          Essaie de poster ton code sur plusieurs lignes la prochaine fois. J'ai du temps à perdre donc je me suis amusé à le développer :

          if (
          translation.x + collision.x <= entity->translation.x + width &&
          translation.x + width >= entity->translation.x &&
          translation.y <= entity->translation.y + height &&
          translation.y + height >= entity->translation.y &&
          translation.z <= entity->translation.z + depth &&
          translation.z + depth >= entity->translation.z) 
          { 
          translation.x = entity->translation.x + (translation.x > entity->translation.x ? width : -width);
          collision.x *= -1; 
          }

          Et j'ai quelques questions :

          • C'est quoi translation ?
          • C'est quoi collision ?
          • width et height c'est la taille de quoi ?
          • Partager sur Facebook
          • Partager sur Twitter
            31 mai 2021 à 9:16:29

            Salut,

            Sans même parler du code, je pense que tu tombes dans le piège des collisions :

            "Que fait on quand on est coincé dans un mur ?" -> on revoir son code.

            Car en effet, on ne doit pas être coincé dans un mur, jamais !

            L'idée quand tu te déplaces, ce n'est pas de te déplacer puis voir si tu touches.

            C'est de déplacer une copie, de voir si la copie touche, et si elle ne touche pas alors on valide le déplacement de l'original, sinon on ne touche pas à l'original.

            Ainsi, on n'est jamais dans le mur. C'est ça qu'il faut revoir.

            * note que dans certains jeux comme Megaman 2 sur Nes, ils avaient fait des algos d'éjection à droite dans les cas improbable ou on serait quand même dans le mur, et les speedrunner s'en servent pour skipper des parties entières de niveaux.

            • Partager sur Facebook
            • Partager sur Twitter

            Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

            Anonyme
              31 mai 2021 à 19:17:24

              Fvirtman a écrit:

              C'est de déplacer une copie, de voir si la copie touche, et si elle ne touche pas alors on valide le déplacement de l'original, sinon on ne touche pas à l'original.


              C'est ça, collision.

              Raynobrak a écrit:

              C'est quoi translation?

              • width et height c'est la taille de quoi ?


              Translation, c'est la position du joueur.

              Width et height, c'est la taille de l'objet qui va entrer en collision ou non.

              Deedolith a écrit:

              Basiquement, pour chaque entité, tu définit une boite englobante.

              La détection de collision vérifie juste si 2 boites s'entrecroisent.

              Quand à faire du prédictif, tu dois d'abord calculer la prochaine position des entités, et ensuite faire le test de collision.


              Comme Fvirtman l'a dit, j'ai crée une copie de la position. Grâce à width, height etdepth, je fabrique une boîte englobante qui change de taille selon la taille de l'objet. Enfaite, mon problème est que en touchant le bord d'un modèle (un cube, par exemple), je me retrouve bloqué et impossible de bouger.

              Voici le code en plus joli :

              for (auto &entity : entities)
              	{
              		if (entity == this)
              			continue;
              
              		const auto &texturedModel = entity->texturedModel;
              		const auto &model = texturedModel.model;
              
              		const auto &width = model.size.x * entity->scale + this->texturedModel.model.size.x * scale;
              		const auto &height = model.size.y * entity->scale;
              		const auto &depth = model.size.z * entity->scale;
              
              		if (translation.x + collision.x <= entity->translation.x + width
              				&& translation.x + width >= entity->translation.x && translation.y <= entity->translation.y + height
              				&& translation.y + height >= entity->translation.y && translation.z <= entity->translation.z + depth
              				&& translation.z + depth >= entity->translation.z)
              		{
              			translation.x = entity->translation.x + (translation.x > entity->translation.x ? width : -width);
              			collision.x *= -1;
              
              			break;
              		}
              	}


              TexturedModel est une classe qui regroupe le modèle et la texture de l'entité. model.size est un vec3 (j'utilise glm) représentant la taille du modèle.

              La ligne

              translation.x = entity->translation.x + (translation.x > entity->translation.x ? width : -width);

              sert à replacer le joueur à côté de l'entité s'il est rentré dedans.

              -
              Edité par Anonyme 31 mai 2021 à 19:24:23

              • Partager sur Facebook
              • Partager sur Twitter
                31 mai 2021 à 19:37:23

                Si collision => détection du point d'impact => bilan des forces + conservation de la quantité de mouvement => ...

                Je ne vois rien de tout cela.

                • Partager sur Facebook
                • Partager sur Twitter
                Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                Anonyme
                  31 mai 2021 à 19:52:53

                  Faisons plus simple. Voici mon code :

                  AABB.h

                  #ifndef AABB_H
                  #define AABB_H
                  
                  class AABB
                  {
                  public:
                      float x, y, z, width, height, depth;
                      bool collide(const AABB &aabb);
                  };
                  
                  #endif // AABB_H
                  

                  AABB.cpp

                  #include "AABB.h"
                  
                  bool AABB::collide(const AABB &aabb)
                  {
                      return x <= aabb.x + aabb.width && x + width >= aabb.x &&
                             y <= aabb.y + aabb.height && y + height >= aabb.y &&
                             z <= aabb.z + aabb.depth && z + depth >= aabb.z;
                  }
                  

                  Camera.cpp

                  #include "Camera.h"
                  #include "AABB.h"
                  
                  #include <SFML/Window.hpp>
                  #include <glm/trigonometric.hpp>
                  
                  void Camera::update(const Entity &entity)
                  {
                      rotation.x = glm::radians((float) sf::Mouse::getPosition().y);
                      rotation.y = glm::radians((float) sf::Mouse::getPosition().x);
                  
                      float speed = 0.1f;
                  
                      if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
                      {
                          collision.z -= cosf(rotation.y) * speed;
                          collision.x += sinf(rotation.y) * speed;
                      }
                      if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
                      {
                          collision.z += cosf(rotation.y) * speed;
                          collision.x -= sinf(rotation.y) * speed;
                      }
                      if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
                      {
                          collision.x -= cosf(rotation.y) * speed;
                          collision.z -= sinf(rotation.y) * speed;
                      }
                      if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
                      {
                          collision.x += cosf(rotation.y) * speed;
                          collision.z += sinf(rotation.y) * speed;
                      }
                  
                      const auto &texturedModel = entity.texturedModel;
                      const auto &model = texturedModel.model;
                  
                      const auto &width = model.size.x;
                      const auto &height = model.size.y;
                      const auto &depth = model.size.z;
                  
                      AABB cameraAabb = {position.x + collision.x - 0.5f, position.y, position.z, 1, 1, 1};
                      AABB entityAabb = {entity.translation.x, entity.translation.y, entity.translation.z, width, height, depth};
                  
                      if (cameraAabb.collide(entityAabb))
                      {
                          collision.x = 0;
                      }
                  
                      cameraAabb = {position.x + collision.x + 0.5f, position.y, position.z, 1, 1, 1};
                  
                      if (cameraAabb.collide(entityAabb))
                      {
                          collision.x = 0;
                      }
                  
                      cameraAabb = {position.x, position.y, position.z + collision.z - 0.5f, 1, 1, 1};
                  
                      if (cameraAabb.collide(entityAabb))
                      {
                          collision.z = 0;
                      }
                  
                      cameraAabb = {position.x, position.y, position.z + collision.z + 0.5f, 1, 1, 1};
                  
                      if (cameraAabb.collide(entityAabb))
                      {
                          collision.z = 0;
                      }
                  
                      position.x += collision.x;
                      position.y += collision.y;
                      position.z += collision.z;
                  
                      collision.x = 0;
                      collision.z = 0;
                  }
                  

                  Ce code est un autre que celui posté au début. Translation s'appelle maintenant position.

                  entity est un cube, pour facilement utiliser des boîtes.

                  Ce code n'est pas bien optimisé mais je m'en occuperai plus tard.



                  • Partager sur Facebook
                  • Partager sur Twitter
                    31 mai 2021 à 20:12:54

                    Oui, Et ?

                    Ton code détecte bien un chevauchement entre ta "camera après déplacement" et ton entité, et si chevauchement, annuler le déplacement de "camera", donc forcément, ça fait ce que tu décris.

                    Donc, si tu ne veux pas faire une simulation "physique" (cf. l’enchaînement de tâches indiquées dans mon précédent post), tu veux quoi comme comportement ???

                    Là, tu as implémenté le comportement "je reste figé à la position de départ" donc, où est la divergence ???

                    • Partager sur Facebook
                    • Partager sur Twitter
                    Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                    Anonyme
                      31 mai 2021 à 20:30:47

                      Finalement, j'ai enfin trouvé une solution. Je me suis souvenu d'un programme que j'avais fait sur lequel les collisions étaient parfaites. J'ai repris son code et le voici :

                      Camera.h

                      #ifndef CAMERA_H
                      #define CAMERA_H
                      
                      #include <glm/vec3.hpp>
                      #include "Entity.h"
                      
                      class Camera
                      {
                      private:
                          glm::vec3 collision = {};
                          inline bool collide(const Entity &entity, const float &width, const float &height, const float &depth, const float &x, const float &y, const float &z);
                      
                      public:
                          glm::vec3 position = {}, rotation = {};
                          void update(const Entity &entity);
                      };
                      
                      #endif // CAMERA_H
                      


                      Camera.cpp

                      #include "Camera.h"
                      #include "AABB.h"
                      
                      #include <SFML/Window.hpp>
                      #include <glm/trigonometric.hpp>
                      
                      void Camera::update(const Entity &entity)
                      {
                          rotation.x = glm::radians((float) sf::Mouse::getPosition().y);
                          rotation.y = glm::radians((float) sf::Mouse::getPosition().x);
                      
                          float speed = 0.1f;
                      
                          if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
                          {
                              collision.z -= cosf(rotation.y) * speed;
                              collision.x += sinf(rotation.y) * speed;
                          }
                          if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
                          {
                              collision.z += cosf(rotation.y) * speed;
                              collision.x -= sinf(rotation.y) * speed;
                          }
                          if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
                          {
                              collision.x -= cosf(rotation.y) * speed;
                              collision.z -= sinf(rotation.y) * speed;
                          }
                          if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
                          {
                              collision.x += cosf(rotation.y) * speed;
                              collision.z += sinf(rotation.y) * speed;
                          }
                          if (sf::Keyboard::isKeyPressed(sf::Keyboard::Space))
                              collision.y += speed;
                          if (sf::Keyboard::isKeyPressed(sf::Keyboard::LShift))
                              collision.y -= speed;
                      
                          const auto &texturedModel = entity.texturedModel;
                          const auto &model = texturedModel.model;
                      
                          const auto &width = model.size.x;
                          const auto &height = model.size.y;
                          const auto &depth = model.size.z;
                      
                          if (!collide(entity, width, height, depth, collision.x, 0, 0))
                              position.x += collision.x;
                          if (!collide(entity, width, height, depth, 0, collision.y, 0))
                              position.y += collision.y;
                          if (!collide(entity, width, height, depth, 0, 0, collision.z))
                              position.z += collision.z;
                      
                          collision.x = 0;
                          collision.y = 0;
                          collision.z = 0;
                      }
                      
                      inline bool Camera::collide(const Entity &entity, const float &width, const float &height, const float &depth, const float &x, const float &y, const float &z)
                      {
                          AABB entityAabb = {entity.translation.x, entity.translation.y, entity.translation.z, width, height, depth};
                      
                          AABB cameraAabb = {position.x + x - 0.5f, position.y + y - 0.5f, position.z + z - 0.5f, 1, 1, 1};
                          if (cameraAabb.collide(entityAabb))
                              return true;
                      
                          cameraAabb = {position.x + x + 0.5f, position.y + y - 0.5f, position.z + z - 0.5f, 1, 1, 1};
                          if (cameraAabb.collide(entityAabb))
                              return true;
                      
                          cameraAabb = {position.x + x + 0.5f, position.y + y + 0.5f, position.z + z - 0.5f, 1, 1, 1};
                          if (cameraAabb.collide(entityAabb))
                              return true;
                      
                          cameraAabb = {position.x + x - 0.5f, position.y + y + 0.5f, position.z + z - 0.5f, 1, 1, 1};
                          if (cameraAabb.collide(entityAabb))
                              return true;
                      
                          cameraAabb = {position.x + x - 0.5f, position.y + y - 0.5f, position.z + z + 0.5f, 1, 1, 1};
                          if (cameraAabb.collide(entityAabb))
                              return true;
                      
                          cameraAabb = {position.x + x + 0.5f, position.y + y - 0.5f, position.z + z + 0.5f, 1, 1, 1};
                          if (cameraAabb.collide(entityAabb))
                              return true;
                      
                          cameraAabb = {position.x + x + 0.5f, position.y + y + 0.5f, position.z + z + 0.5f, 1, 1, 1};
                          if (cameraAabb.collide(entityAabb))
                              return true;
                      
                          cameraAabb = {position.x + x - 0.5f, position.y + y + 0.5f, position.z + z + 0.5f, 1, 1, 1};
                          if (cameraAabb.collide(entityAabb))
                              return true;
                      
                          return false;
                      }
                      



                      -
                      Edité par Anonyme 31 mai 2021 à 20:31:55

                      • Partager sur Facebook
                      • Partager sur Twitter
                        31 mai 2021 à 21:39:43

                        Heu, à part la prise en compte de la 3ème dimension, c'est quoi la différence ?

                        • Partager sur Facebook
                        • Partager sur Twitter
                        Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                        Anonyme
                          1 juin 2021 à 7:44:52

                          Euh... Je ne sais pas trop, mais ça marche bien comma ça.
                          • Partager sur Facebook
                          • Partager sur Twitter
                            1 juin 2021 à 10:40:38

                            Je ne suis pas convaincu que la fonction membre collide() soit une bonne idée.
                            Une fonction libre sera plus appropriée a mon avis (plus générique, donc plus souple)

                            Je me souvient d'un tetris, le principe etait extremement simple:
                            1) Instanciation temporaire d'une piece à sa futur position.
                            2) Comparaison de la position des carrés de la piece avec ceux de l'aire de jeux (detection de collision).
                            3) S'il n'y a pas de collision, on effectue le mouvement.
                            4) S'il y a collision, on ne fait rien.

                            J'ai l'impression que tu as effectué le mouvement d'abord (puisque tu veux annuler), c'est l'inverse qu'il faut faire.

                            -
                            Edité par Deedolith 1 juin 2021 à 10:40:55

                            • Partager sur Facebook
                            • Partager sur Twitter
                            Anonyme
                              12 juin 2021 à 10:50:09

                              bacelar a écrit:

                              Heu, à part la prise en compte de la 3ème dimension, c'est quoi la différence ?


                              Finalement, tu as raison. Le bug est toujours présent mais j'ai trouvé une autre technique pour le résoudre. Je n'ai plus aucun problème de collision (après trois mois, quand même :p) !


                              C'était simple, il fallait faire :

                              for (auto &entity : entities)
                                  {
                                      if (entity == this || entity->noHitbox)
                                          continue;
                              
                                      const auto &texturedModel = entity->texturedModel;
                                      const auto &model = texturedModel.model;
                              
                                      const auto &width = model.size.x * entity->scale + this->texturedModel.model.size.x * scale;
                                      const auto &height = model.size.y * entity->scale + this->texturedModel.model.size.y * scale;
                                      const auto &depth = model.size.z * entity->scale + this->texturedModel.model.size.z * scale;
                              
                                      AABB playerAabb = {translation.x + velocity.x, translation.y, translation.z, width, height, depth};
                                      AABB entityAabb = {entity->translation.x, entity->translation.y, entity->translation.z, width, height, depth};
                              
                                      if (playerAabb.collide(entityAabb))
                                      {
                                          velocity.x *= -1;
                                          break;
                                      }
                                  }




                              MO9845 a écrit:

                              for (auto &entity : entities)
                              	{
                              		if (entity == this)
                              			continue;
                              
                              		const auto &texturedModel = entity->texturedModel;
                              		const auto &model = texturedModel.model;
                              
                              		const auto &width = model.size.x * entity->scale + this->texturedModel.model.size.x * scale;
                              		const auto &height = model.size.y * entity->scale;
                              		const auto &depth = model.size.z * entity->scale;
                              
                              		if (translation.x + collision.x <= entity->translation.x + width
                              				&& translation.x + width >= entity->translation.x && translation.y <= entity->translation.y + height
                              				&& translation.y + height >= entity->translation.y && translation.z <= entity->translation.z + depth
                              				&& translation.z + depth >= entity->translation.z)
                              		{
                              			translation.x = entity->translation.x + (translation.x > entity->translation.x ? width : -width);
                              			collision.x *= -1;
                              
                              			break;
                              		}
                              	}

                              J'avais fait une erreur que je ne suis pas prêt de refaire.


                              Velocity, c'est le nouveau nom de collision.



                              -
                              Edité par Anonyme 12 juin 2021 à 10:54:37

                              • Partager sur Facebook
                              • Partager sur Twitter

                              AABB bloqué sur les coins

                              × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                              × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                              • Editeur
                              • Markdown