added ball to ball collisions
[physics.git] / src / collisionHandler.cpp
1 /*
2  *  Copyright (C) 2008 Patrik Gornicz, Gornicz_P (at) hotmail (dot) com.
3  *
4  *  This program is free software: you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation, either version 3 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include "collisionHandler.h"
19 #include "debug.h"
20
21 #include "Vector2.h"
22
23 #include "Entities/Ball.h"
24 #include "Entities/PhysicsEntity.h"
25
26 #include "CollisionInfo.h"
27
28 /// ***** Private Class Header *****
29
30 /// ***** Private Method Headers *****
31
32 void applyCollisionAt(PhysicsEntity* p1, PhysicsEntity* p2, float time_step);
33 void applyCollisionAt(Ball* b1, Ball* b2, float time_step);
34
35 CollisionInfo* getInfoAt(Ball* b1, Ball* b2, float time_step);
36
37 /// ***** Private Variables *****
38
39 /// ***** Initializers/Cleaners *****
40
41 void collision::init()
42 {
43
44 }
45 void collision::clean()
46 {
47
48 }
49
50 /// ***** Public Methods *****
51
52 void collision::update(setPhys sp, float time_step)
53 {
54     for( setPhys::iterator it1 = sp.begin();
55          it1 != sp.end();
56          it1++ )
57     {
58         for( setPhys::iterator it2 = sp.begin();
59                 it2 != sp.end();
60                 it2++ )
61         {
62             if( *it1 != *it2 )
63             {
64                 applyCollisionAt(*it1, *it2, time_step);
65             }
66         }
67     }
68
69 }
70
71 /// ***** Private Methods *****
72
73 void applyCollisionAt(PhysicsEntity* p1, PhysicsEntity* p2, float time_step)
74 {
75     Ball* b1 = dynamic_cast<Ball*>(p1);
76     Ball* b2 = dynamic_cast<Ball*>(p2);
77
78     if( b1 != NULL && b2 != NULL )
79     {
80         applyCollisionAt(b1, b2, time_step);
81         return;
82     }
83
84 #ifdef WARNINGS
85     cerr << "ENTITY TYPE NOT SUPPORTED BY applyCollisionAt()!!" << endl;
86 #endif
87 }
88
89 void applyCollisionAt(Ball* b1, Ball* b2, float time_step)
90 {
91     // /*
92     CollisionInfo* info = getInfoAt(b1, b2, time_step);
93
94     if(info == NULL)
95         return;
96
97     // a few values to simplify the equations
98     Vector2 normal = info->normal;
99     Vector2 point = info->point;
100
101     delete info;
102
103     float m1 = b1->mass;
104     float m2 = b2->mass;
105
106     float e = (b1->CoR + b2->CoR) / 2;
107
108     Vector2 v1 = b1->velocityAt(time_step);
109     Vector2 v2 = b2->velocityAt(time_step);
110
111
112     float iTop = -(e + 1) * (v1 - v2).dot(normal);
113
114     // otherwise the collision happened and we do the math the below assumes
115     // collisions have no friction
116
117     float impulse = iTop / (normal.dot(normal) * (1 / m1 + 1 / m2));
118
119     b1->applyImpulse(impulse / m1 * normal, point);
120     b2->applyImpulse(-impulse / m2 * normal, point);
121     // */
122 }
123
124 CollisionInfo* getInfoAt(Ball* b1, Ball* b2, float time_step)
125 {
126     // a few values to simplify the equations
127     float r1 = b1->radius;
128     float r2 = b2->radius;
129
130     Vector2 p1 = b1->positionAt(time_step);
131     Vector2 p2 = b2->positionAt(time_step);
132     Vector2 v1 = b1->velocityAt(time_step);
133     Vector2 v2 = b2->velocityAt(time_step);
134
135     // quick binding box check
136     if (p1.x - r1 > p2.x + r2
137      || p1.x + r1 < p2.x - r2
138      || p1.y - r1 > p2.y + r2
139      || p1.y + r1 < p2.y - r2)
140         return NULL;
141
142     // test if not touching
143     if ((p1 - p2).sqrLength() >= (r1 + r2)*(r1 + r2))
144         return NULL;
145
146     // test if they are moving apart in some way if they aren't it's likely
147     // that they collided last frame and are still overlapping
148
149     if ((v1 - v2).dot(p1 - p2) >= 0)
150         return NULL;
151
152     return new CollisionInfo(p1 - (p1 - p2) * r1 / (r1 + r2), p1 - p2);
153 }