converted game object arrays to std::vector
[supertux.git] / src / collision.cpp
1 //
2 // C Implementation: collision
3 //
4 // Description:
5 //
6 //
7 // Author: Tobias Glaesser <tobi.web@gmx.de>, (C) 2004
8 //
9 // Copyright: See COPYING file that comes with this distribution
10 //
11 //
12
13 #include "defines.h"
14 #include "collision.h"
15 #include "bitmask.h"
16 #include "scene.h"
17
18 int rectcollision(base_type* one, base_type* two)
19 {
20
21   if (one->x >= two->x - one->width + 1 &&
22       one->x <= two->x + two->width - 1  &&
23       one->y >= two->y - one->height + 1&&
24       one->y <= two->y + two->height - 1)
25     {
26       return YES;
27     }
28   else
29     {
30       return NO;
31     }
32 }
33
34 int rectcollision_offset(base_type* one, base_type* two, float off_x, float off_y)
35 {
36   if (one->x >= two->x - one->width +off_x + 1 &&
37       one->x <= two->x + two->width + off_x - 1 &&
38       one->y >= two->y - one->height + off_y + 1 &&
39       one->y <= two->y + two->height + off_y - 1)
40     {
41       return YES;
42     }
43   else
44     {
45       return NO;
46     }
47 }
48
49 int collision_object_map(base_type* pbase)
50 {
51   int v,h,i;
52
53   v = (int)pbase->height / 16;
54   h = (int)pbase->width / 16;
55
56   if(issolid(pbase->x + 1, pbase->y + 1) ||
57       issolid(pbase->x + pbase->width -1, pbase->y + 1) ||
58       issolid(pbase->x +1, pbase->y + pbase->height -1) ||
59       issolid(pbase->x + pbase->width -1, pbase->y + pbase->height - 1))
60     return YES;
61
62   for(i = 1; i < h; ++i)
63     {
64       if(issolid(pbase->x + i*16,pbase->y + 1))
65         return YES;
66     }
67
68   for(i = 1; i < h; ++i)
69     {
70       if(  issolid(pbase->x + i*16,pbase->y + pbase->height - 1))
71         return YES;
72     }
73
74   for(i = 1; i < v; ++i)
75     {
76       if(  issolid(pbase->x + 1, pbase->y + i*16))
77         return YES;
78     }
79   for(i = 1; i < v; ++i)
80     {
81       if(  issolid(pbase->x + pbase->width - 1, pbase->y + i*16))
82         return YES;
83     }
84
85   return NO;
86 }
87
88
89 int collision_swept_object_map(base_type* old, base_type* current)
90 {
91   int steps; /* Used to speed up the collision tests, by stepping every 16pixels in the path. */
92   int h;
93   float i;
94   float lpath; /* Holds the longest path, which is either in X or Y direction. */
95   float xd,yd; /* Hold the smallest steps in X and Y directions. */
96   float temp, xt, yt; /* Temporary variable. */
97
98   lpath = 0;
99   xd = 0;
100   yd = 0;
101
102   if(old->x == current->x && old->y == current->y)
103     {
104       return 0;
105     }
106   else if(old->x == current->x && old->y != current->y)
107     {
108       lpath = current->y - old->y;
109       if(lpath < 0)
110         {
111           yd = -1;
112           lpath = -lpath;
113         }
114       else
115         {
116           yd = 1;
117         }
118
119       h = 1;
120       xd = 0;
121
122     }
123   else if(old->x != current->x && old->y == current->y)
124     {
125       lpath = current->x - old->x;
126       if(lpath < 0)
127         {
128           xd = -1;
129           lpath = -lpath;
130         }
131       else
132         {
133           xd = 1;
134         }
135       h = 2;
136       yd = 0;
137     }
138   else
139     {
140       lpath = current->x - old->x;
141       if(lpath < 0)
142         lpath = -lpath;
143       if(current->y - old->y > lpath || old->y - current->y > lpath)
144         lpath = current->y - old->y;
145       if(lpath < 0)
146         lpath = -lpath;
147       h = 3;
148       xd = (current->x - old->x) / lpath;
149       yd = (current->y - old->y) / lpath;
150     }
151
152   steps = (int)(lpath / (float)16);
153
154   old->x += xd;
155   old->y += yd;
156
157   for(i = 0; i <= lpath; old->x += xd, old->y += yd, ++i)
158     {
159       if(steps > 0)
160         {
161           old->y += yd*16.;
162           old->x += xd*16.;
163           steps--;
164         }
165
166       if(collision_object_map(old))
167         {
168           switch(h)
169             {
170             case 1:
171               current->y = old->y - yd;
172               while(collision_object_map(current))
173                 current->y -= yd;
174               break;
175             case 2:
176               current->x = old->x - xd;
177               while(collision_object_map(current))
178                 current->x -= xd;
179               break;
180             case 3:
181               xt = current->x;
182               yt = current->y;
183               current->x = old->x - xd;
184               current->y = old->y - yd;
185               while(collision_object_map(current))
186                 {
187                   current->x -= xd;
188                   current->y -= yd;
189                 }
190
191               temp = current->x;
192               current->x = xt;
193               if(!collision_object_map(current))
194                 break;
195               current->x = temp;
196               temp = current->y;
197               current->y = yt;
198
199               if(!collision_object_map(current))
200                 {
201                   break;
202                 }
203               else
204                 {
205                   current->y = temp;
206                   while(!collision_object_map(current))
207                     current->y += yd;
208                   current->y -= yd;
209                   break;
210                 }
211
212               break;
213             default:
214               break;
215             }
216           break;
217         }
218     }
219
220   *old = *current;
221 return 0;
222 }
223
224 void collision_handler()
225 {
226   unsigned int i,j;
227
228   /* CO_BULLET & CO_BADGUY check */
229   for(i = 0; i < bullets.size(); ++i)
230     {
231           for(j = 0; j < bad_guys.size(); ++j)
232             {
233               if(bad_guys[j].dying == NO)
234                 {
235                   if(rectcollision(&bullets[i].base,&bad_guys[j].base) == YES)
236                     {
237                       /* We have detected a collision and now call the collision functions of the collided objects. */
238                       bullet_collision(&bullets[i], CO_BADGUY);
239                       badguy_collision(&bad_guys[j], &bullets[i], CO_BULLET);
240                     }
241                 }
242             }
243     }
244
245   /* CO_BADGUY & CO_BADGUY check */
246   for(i = 0; i < bad_guys.size(); ++i)
247     {
248       if(bad_guys[i].dying == NO)
249         {
250           for(j = i+1; j < bad_guys.size(); ++j)
251             {
252               if(j != i && bad_guys[j].dying == NO)
253                 {
254                   if(rectcollision(&bad_guys[i].base,&bad_guys[j].base) == YES)
255                     {
256                       /* We have detected a collision and now call the collision functions of the collided objects. */
257                       badguy_collision(&bad_guys[j], &bad_guys[i], CO_BADGUY);
258                       badguy_collision(&bad_guys[i], &bad_guys[j], CO_BADGUY);
259                     }
260                 }
261             }
262         }
263     }
264
265
266
267   /* CO_BADGUY & CO_PLAYER check */
268   for(i = 0; i < bad_guys.size(); ++i)
269     {
270           if(bad_guys[i].dying == NO && rectcollision_offset(&bad_guys[i].base,&tux.base,0,0) == YES )
271             {
272               /* We have detected a collision and now call the collision functions of the collided objects. */
273               if (tux.previous_base.y < tux.base.y &&
274                   tux.previous_base.y + tux.previous_base.height < bad_guys[i].base.y + bad_guys[i].base.height/2 &&
275                   bad_guys[i].kind != BAD_MONEY && bad_guys[i].mode != HELD)
276                 {
277                   badguy_collision(&bad_guys[i], &tux, CO_PLAYER);
278                 }
279               else
280                 {
281                   player_collision(&tux, &bad_guys[i], CO_BADGUY);
282                 }
283             }
284     }
285
286   /* CO_UPGRADE & CO_PLAYER check */
287   for(i = 0; i < upgrades.size(); ++i)
288     {
289           if(rectcollision(&upgrades[i].base,&tux.base) == YES)
290             {
291               /* We have detected a collision and now call the collision functions of the collided objects. */
292               upgrade_collision(&upgrades[i], &tux, CO_PLAYER);
293             }
294     }
295
296 }
297
298