ball collisions now optimized
[physics.git] / src / collisionManager.cpp
index 39f6396..9db130e 100644 (file)
 
 /// ***** Private Method Headers *****
 
-void applyCollisionAt(PhysicsEntity* p1, PhysicsEntity* p2);
-void applyCollisionAt(Ball* b1, Ball* b2);
+void clearEntities();
+void placeEntity(PhysicsEntity* p);
+void updateEntities();
 
-CollisionInfo* getInfoAt(Ball* b1, Ball* b2);
+void applyCollision(PhysicsEntity* p1, PhysicsEntity* p2);
+void applyCollision(Ball* b1, Ball* b2);
+
+bool getInfo(Ball* b1, Ball* b2, CollisionInfo* cInfo);
 
 /// ***** Private Variables *****
 
+const int xDivisions = 20;
+const int yDivisions = 16;
+const int screenX    = 800;
+const int screenY    = 600;
+
+setPhys divisions[xDivisions][yDivisions];
+
 /// ***** Initializers/Cleaners *****
 
 void collision::init()
@@ -51,52 +62,120 @@ void collision::clean()
 
 void collision::update(setPhys& sp)
 {
-    for( setPhys::iterator it1 = sp.begin();
-         it1 != sp.end();
-         it1++ )
+    clearEntities();
+
+    for( setPhys::iterator it = sp.begin();
+         it != sp.end();
+         it++ )
+    {
+        placeEntity(*it);
+    }
+
+    updateEntities();
+}
+
+/// ***** Private Methods *****
+
+void clearEntities()
+{
+    for( int x = 0;
+             x < xDivisions;
+             x++ )
     {
-        for( setPhys::iterator it2 = sp.begin();
-                it2 != sp.end();
-                it2++ )
+        for( int y = 0;
+                 y < yDivisions;
+                 y++ )
         {
-            if( *it1 != *it2 )
-            {
-                applyCollisionAt(*it1, *it2);
-            }
+            divisions[x][y].clear();
         }
     }
+}
 
+void placeEntity(PhysicsEntity* p)
+{
+    Ball* b = dynamic_cast<Ball*>(p);
+
+    if( b == NULL )
+    {
+        DPF(0, "ENTITY TYPE NOT SUPPORTED BY placeEntity()!!");
+        return;
+    }
+
+    const float& xb     = b->positionRaw().x;
+    const float& yb     = b->positionRaw().y;
+    const float& rad    = b->radius;
+
+    for( int x =  static_cast<int>( (xb - rad) / (screenX / xDivisions) );
+             x <= static_cast<int>( (xb + rad) / (screenX / xDivisions) );
+             x++ )
+    {
+        if(x < 0 || xDivisions <= x)
+            break;
+
+        for( int y =  static_cast<int>( (yb - rad) / (screenY / yDivisions) );
+                 y <= static_cast<int>( (yb + rad) / (screenY / yDivisions) );
+                 y++ )
+        {
+            if(y < 0 || yDivisions <= y)
+                break;
+
+            divisions[x][y].insert(p);
+        }
+    }
 }
 
-/// ***** Private Methods *****
+void updateEntities()
+{
+    for( int x = 0;
+             x < xDivisions;
+             x++ )
+    {
+        for( int y = 0;
+                 y < yDivisions;
+                 y++ )
+        {
+            for( setPhys::iterator it1 = divisions[x][y].begin();
+                 it1 != divisions[x][y].end();
+                 it1++ )
+            {
+                for( setPhys::iterator it2 = divisions[x][y].begin();
+                     it2 != divisions[x][y].end();
+                     it2++ )
+                {
+                    if( *it1 != *it2 )
+                    {
+                        applyCollision(*it1, *it2);
+                    }
+                }
+            }
+        }
+    }
+}
 
-void applyCollisionAt(PhysicsEntity* p1, PhysicsEntity* p2)
+void applyCollision(PhysicsEntity* p1, PhysicsEntity* p2)
 {
     Ball* b1 = dynamic_cast<Ball*>(p1);
     Ball* b2 = dynamic_cast<Ball*>(p2);
 
     if( b1 != NULL && b2 != NULL )
     {
-        applyCollisionAt(b1, b2);
+        applyCollision(b1, b2);
         return;
     }
 
-    DPF(0, "ENTITY TYPE NOT SUPPORTED BY applyCollisionAt()!!");
+    DPF(0, "ENTITY TYPE NOT SUPPORTED BY applyCollision()!!");
 }
 
-void applyCollisionAt(Ball* b1, Ball* b2)
+void applyCollision(Ball* b1, Ball* b2)
 {
-    // /*
-    CollisionInfo* info = getInfoAt(b1, b2);
+    CollisionInfo   cInfo;
 
-    if(info == NULL)
+    if(!getInfo(b1, b2, &cInfo))
         return;
 
     // a few values to simplify the equations
-    Vector2 normal = info->normal;
-    Vector2 point = info->point;
-
-    delete info;
+    const Vector2& normal = cInfo.normal;
+    const Vector2& point  = cInfo.point;
 
     float m1 = b1->mass;
     float m2 = b2->mass;
@@ -116,10 +195,9 @@ void applyCollisionAt(Ball* b1, Ball* b2)
 
     b1->applyImpulse(impulse / m1 * normal, point);
     b2->applyImpulse(-impulse / m2 * normal, point);
-    // */
 }
 
-CollisionInfo* getInfoAt(Ball* b1, Ball* b2)
+bool getInfo(Ball* b1, Ball* b2, CollisionInfo* pcInfo)
 {
     // a few values to simplify the equations
     float r1 = b1->radius;
@@ -135,17 +213,20 @@ CollisionInfo* getInfoAt(Ball* b1, Ball* b2)
      || p1.x + r1 < p2.x - r2
      || p1.y - r1 > p2.y + r2
      || p1.y + r1 < p2.y - r2)
-        return NULL;
+        return false;
 
     // test if not touching
     if ((p1 - p2).sqrLength() >= (r1 + r2)*(r1 + r2))
-        return NULL;
+        return false;
 
     // test if they are moving apart in some way if they aren't it's likely
     // that they collided last frame and are still overlapping
 
     if ((v1 - v2).dot(p1 - p2) >= 0)
-        return NULL;
+        return false;
+
+    pcInfo->point   = p1 - (p1 - p2) * r1 / (r1 + r2);
+    pcInfo->normal  = p1 - p2;
 
-    return new CollisionInfo(p1 - (p1 - p2) * r1 / (r1 + r2), p1 - p2);
+    return true;
 }