wip: advanced collisions
[physics.git] / src / collisionManager.cpp
CommitLineData
54fe85c5
PG
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
0ac1dc80 18#include "collisionManager.h"
54fe85c5
PG
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
14597cf6
PG
32void clearEntities();
33void placeEntity(PhysicsEntity* p);
34void updateEntities();
54fe85c5 35
14597cf6
PG
36void applyCollision(PhysicsEntity* p1, PhysicsEntity* p2);
37void applyCollision(Ball* b1, Ball* b2);
38
39bool getInfo(Ball* b1, Ball* b2, CollisionInfo* cInfo);
54fe85c5
PG
40
41/// ***** Private Variables *****
42
14597cf6
PG
43const int xDivisions = 20;
44const int yDivisions = 16;
45
46setPhys divisions[xDivisions][yDivisions];
47
54fe85c5
PG
48/// ***** Initializers/Cleaners *****
49
50void collision::init()
51{
52
53}
54void collision::clean()
55{
56
57}
58
59/// ***** Public Methods *****
60
2869e2e8 61void collision::update(setPhys& sp)
54fe85c5 62{
14597cf6
PG
63 clearEntities();
64
65 for( setPhys::iterator it = sp.begin();
66 it != sp.end();
67 it++ )
54fe85c5 68 {
14597cf6
PG
69 placeEntity(*it);
70 }
71
72 updateEntities();
73}
74
75/// ***** Private Methods *****
76
77void clearEntities()
78{
79 for( int x = 0;
80 x < xDivisions;
81 x++ )
82 {
83 for( int y = 0;
84 y < yDivisions;
85 y++ )
54fe85c5 86 {
14597cf6 87 divisions[x][y].clear();
54fe85c5
PG
88 }
89 }
14597cf6 90}
54fe85c5 91
14597cf6
PG
92void placeEntity(PhysicsEntity* p)
93{
94 Ball* b = dynamic_cast<Ball*>(p);
95
96 if( b == NULL )
97 {
98 DPF(0, "ENTITY TYPE NOT SUPPORTED BY placeEntity()!!");
99 return;
100 }
101
102 const float& xb = b->positionRaw().x;
103 const float& yb = b->positionRaw().y;
104 const float& rad = b->radius;
105
106 for( int x = (int)(xb - rad);
107 x < (int)(xb + rad);
108 x++ )
109 {
110 if(x < 0 || xDivisions <= x)
111 break;
112
113 for( int y = (int)(yb - rad);
114 y < (int)(yb + rad);
115 y++ )
116 {
117 if(y < 0 || yDivisions <= y)
118 break;
119
120 divisions[x][y].insert(p);
121 }
122 }
54fe85c5
PG
123}
124
14597cf6
PG
125void updateEntities()
126{
127 for( int x = 0;
128 x < xDivisions;
129 x++ )
130 {
131 for( int y = 0;
132 y < yDivisions;
133 y++ )
134 {
135 for( setPhys::iterator it1 = divisions[x][y].begin();
136 it1 != divisions[x][y].end();
137 it1++ )
138 {
139 for( setPhys::iterator it2 = divisions[x][y].begin();
140 it2 != divisions[x][y].end();
141 it2++ )
142 {
143 if( *it1 != *it2 )
144 {
145 applyCollision(*it1, *it2);
146 }
147 }
148 }
149 }
150 }
151}
54fe85c5 152
14597cf6 153void applyCollision(PhysicsEntity* p1, PhysicsEntity* p2)
54fe85c5
PG
154{
155 Ball* b1 = dynamic_cast<Ball*>(p1);
156 Ball* b2 = dynamic_cast<Ball*>(p2);
157
158 if( b1 != NULL && b2 != NULL )
159 {
14597cf6 160 applyCollision(b1, b2);
54fe85c5
PG
161 return;
162 }
163
14597cf6 164 DPF(0, "ENTITY TYPE NOT SUPPORTED BY applyCollision()!!");
54fe85c5
PG
165}
166
14597cf6 167void applyCollision(Ball* b1, Ball* b2)
54fe85c5 168{
39643454 169 CollisionInfo cInfo;
54fe85c5 170
14597cf6 171 if(!getInfo(b1, b2, &cInfo))
54fe85c5
PG
172 return;
173
174 // a few values to simplify the equations
39643454
PG
175 const Vector2& normal = cInfo.normal;
176 const Vector2& point = cInfo.point;
54fe85c5
PG
177
178 float m1 = b1->mass;
179 float m2 = b2->mass;
180
181 float e = (b1->CoR + b2->CoR) / 2;
182
2869e2e8
PG
183 Vector2 v1 = b1->velocityRaw();
184 Vector2 v2 = b2->velocityRaw();
54fe85c5
PG
185
186
187 float iTop = -(e + 1) * (v1 - v2).dot(normal);
188
189 // otherwise the collision happened and we do the math the below assumes
190 // collisions have no friction
191
192 float impulse = iTop / (normal.dot(normal) * (1 / m1 + 1 / m2));
193
194 b1->applyImpulse(impulse / m1 * normal, point);
195 b2->applyImpulse(-impulse / m2 * normal, point);
54fe85c5
PG
196}
197
14597cf6 198bool getInfo(Ball* b1, Ball* b2, CollisionInfo* pcInfo)
54fe85c5
PG
199{
200 // a few values to simplify the equations
201 float r1 = b1->radius;
202 float r2 = b2->radius;
203
2869e2e8
PG
204 Vector2 p1 = b1->positionRaw();
205 Vector2 p2 = b2->positionRaw();
206 Vector2 v1 = b1->velocityRaw();
207 Vector2 v2 = b2->velocityRaw();
54fe85c5
PG
208
209 // quick binding box check
210 if (p1.x - r1 > p2.x + r2
211 || p1.x + r1 < p2.x - r2
212 || p1.y - r1 > p2.y + r2
213 || p1.y + r1 < p2.y - r2)
39643454 214 return false;
54fe85c5
PG
215
216 // test if not touching
217 if ((p1 - p2).sqrLength() >= (r1 + r2)*(r1 + r2))
39643454 218 return false;
54fe85c5
PG
219
220 // test if they are moving apart in some way if they aren't it's likely
221 // that they collided last frame and are still overlapping
222
223 if ((v1 - v2).dot(p1 - p2) >= 0)
39643454
PG
224 return false;
225
226 pcInfo->point = p1 - (p1 - p2) * r1 / (r1 + r2);
227 pcInfo->normal = p1 - p2;
54fe85c5 228
39643454 229 return true;
54fe85c5 230}