Advertisement
Zgragselus

Physics collision callbacks

Jun 17th, 2023
938
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 5.30 KB | None | 0 0
  1. /// <summary>
  2. /// Collision record structure
  3. ///
  4. /// Holds single collision information. It should be stored in associative container, where key
  5. /// is collision object B. Together one key-value pair forms single manifold.
  6. /// </summary>
  7. struct CollisionRecord
  8. {
  9.     /// <summary>Collision object A that is collided with</summary>
  10.     btCollisionObject* mObjectA;
  11.  
  12.     /// <summary>Contact point on A</summary>
  13.     btVector3 mPointA;
  14.  
  15.     /// <summary>Contact point on B</summary>
  16.     btVector3 mPointB;
  17.  
  18.     /// <summary>Collision normal on B (Note: on A it is flipped, i.e. -mNormalOnB)</summary>
  19.     btVector3 mNormalOnB;
  20.  
  21.     /// <summary>
  22.     /// Default constructor
  23.     /// </summary>
  24.     CollisionRecord()
  25.     {
  26.         mObjectA = nullptr;
  27.     }
  28.  
  29.     /// <summary>
  30.     /// Parametric constructor
  31.     /// </summary>
  32.     /// <param name="objectA">Collision object with which this contact point collides</param>
  33.     /// <param name="pointA">Contact point on A</param>
  34.     /// <param name="pointB">Contact point on B</param>
  35.     /// <param name="normalOnB">Collision normal on B</param>
  36.     CollisionRecord(btCollisionObject* objectA, const btVector3& pointA, const btVector3& pointB, const btVector3& normalOnB)
  37.     {
  38.         mObjectA = objectA;
  39.         mPointA = pointA;
  40.         mPointB = pointB;
  41.         mNormalOnB = normalOnB;
  42.     }
  43. };
  44.  
  45. /// <summary>
  46. /// List of contact points from previous simulation step
  47. /// </summary>
  48. std::map<btCollisionObject*, CollisionRecord> mContacts;
  49.  
  50. /// <summary>
  51. /// Check collision and call callbacks on game obejcts
  52. ///
  53. /// Update contacts - fire events for on collision enter/on collision exit
  54. /// </summary>
  55. void CheckCollisions()
  56. {
  57.     ////////////////////////////////////////////////////////////////////////////////////////////////
  58.     // The first step is to obtain all contact points in this step
  59.            
  60.     // Associative container holding new contacts from current manifolds
  61.     std::map<btCollisionObject*, CollisionRecord> newContacts;
  62.  
  63.     // Loop through ALL collision pairs
  64.     int numManifolds = mWorld->getDispatcher()->getNumManifolds();
  65.     for (int i = 0; i < numManifolds; i++)
  66.     {
  67.         btPersistentManifold* contactManifold = mWorld->getDispatcher()->getManifoldByIndexInternal(i);
  68.         btCollisionObject* colliderA = (btCollisionObject*)contactManifold->getBody0();
  69.         btCollisionObject* colliderB = (btCollisionObject*)contactManifold->getBody1();
  70.  
  71.         // Loop through ALL contact points in collision pairs
  72.         int numContacts = contactManifold->getNumContacts();
  73.         for (int j = 0; j < numContacts; j++)
  74.         {
  75.             // Check if contact distance is < 0 (i.e. objects penetrate), if so and there isn't a contact
  76.             // in the current list of contacts - add it.
  77.             btManifoldPoint& pt = contactManifold->getContactPoint(j);
  78.             if (pt.getDistance() < 0.0f)
  79.             {
  80.                 const btVector3 ptA = pt.getPositionWorldOnA();
  81.                 const btVector3 ptB = pt.getPositionWorldOnB();
  82.                 const btVector3 normalOnB = pt.m_normalWorldOnB;
  83.  
  84.                 if (newContacts.find(colliderB) == newContacts.end())
  85.                 {
  86.                     newContacts[colliderB] = CollisionRecord(colliderA, ptA, ptB, normalOnB);
  87.                 }
  88.             }
  89.         }
  90.     }
  91.  
  92.     ////////////////////////////////////////////////////////////////////////////////////////////////
  93.     // The second step is to check for newly added contacts
  94.  
  95.     if (!newContacts.empty())
  96.     {
  97.         // Loop through all new contact points and compare them to previous step contact points, the
  98.         // ones that are not present in previous step but are now, are new collisions
  99.         for (std::map<btCollisionObject*, CollisionRecord>::iterator it = newContacts.begin(); it != newContacts.end(); it++)
  100.         {
  101.             // Not found
  102.             if (mContacts.find(it->first) == mContacts.end())
  103.             {
  104.                 // Loop through game object components and call CollisionEnter on each of those
  105.                 Entity* entityB = (Entity*)(it->first->getCollisionShape()->getUserPointer());
  106.  
  107.                 for (auto componentIt = entityB->GameObject().ComponentsItBegin();
  108.                     componentIt != entityB->GameObject().ComponentsItEnd();
  109.                     componentIt++)
  110.                 {
  111.                     Entity* entityA = (Entity*)(it->second.mObjectA->getCollisionShape()->getUserPointer());
  112.  
  113.                     componentIt->second->CollisionEnter(&(entityA->GameObject()));
  114.                     componentIt->second->CollisionEnter(&(entityB->GameObject()));
  115.                 }
  116.             }
  117.             // Found - remove to filter inactive contacts
  118.             else
  119.             {
  120.                 mContacts.erase(it->first);
  121.             }
  122.         }
  123.     }
  124.  
  125.     ////////////////////////////////////////////////////////////////////////////////////////////////
  126.     // The last step is to check for removed contacts
  127.  
  128.     if (!mContacts.empty())
  129.     {
  130.         // Loop through all existing contacts
  131.         for (std::map<btCollisionObject*, CollisionRecord>::iterator it = newContacts.begin(); it != newContacts.end(); it++)
  132.         {
  133.             // For each collision that ends, fire CollisionExit
  134.             // Loop through game object components and call CollisionEnter on each of those
  135.             Entity* entityB = (Entity*)(it->first->getCollisionShape()->getUserPointer());
  136.  
  137.             for (auto componentIt = entityB->GameObject().ComponentsItBegin();
  138.                 componentIt != entityB->GameObject().ComponentsItEnd();
  139.                 componentIt++)
  140.             {
  141.                 Entity* entityA = (Entity*)(it->second.mObjectA->getCollisionShape()->getUserPointer());
  142.  
  143.                 componentIt->second->CollisionExit(&(entityA->GameObject()));
  144.                 componentIt->second->CollisionExit(&(entityB->GameObject()));
  145.             }
  146.         }
  147.     }
  148.  
  149.     // Update previous contacts to the ones in current step
  150.     mContacts = newContacts;
  151. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement