- made some more global variables, local
[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 #include "world.h"
18 #include "level.h"
19 #include "tile.h"
20
21 bool rectcollision(base_type* one, base_type* two)
22 {
23   return (one->x >= two->x - one->width + 1  &&
24           one->x <= two->x + two->width - 1  &&
25           one->y >= two->y - one->height + 1 &&
26           one->y <= two->y + two->height - 1);
27 }
28
29 bool rectcollision_offset(base_type* one, base_type* two, float off_x, float off_y)
30 {
31   return (one->x >= two->x - one->width +off_x + 1 &&
32           one->x <= two->x + two->width + off_x - 1 &&
33           one->y >= two->y - one->height + off_y + 1 &&
34           one->y <= two->y + two->height + off_y - 1);
35 }
36
37 bool collision_object_map(base_type* pbase)
38 {
39   int v = (int)pbase->height / 16;
40   int h = (int)pbase->width / 16;
41
42   if(issolid(pbase->x + 1, pbase->y + 1) ||
43      issolid(pbase->x + pbase->width -1, pbase->y + 1) ||
44      issolid(pbase->x +1, pbase->y + pbase->height -1) ||
45      issolid(pbase->x + pbase->width -1, pbase->y + pbase->height - 1))
46     return true;
47
48   for(int i = 1; i < h; ++i)
49     {
50       if(issolid(pbase->x + i*16,pbase->y + 1))
51         return true;
52     }
53
54   for(int i = 1; i < h; ++i)
55     {
56       if(  issolid(pbase->x + i*16,pbase->y + pbase->height - 1))
57         return true;
58     }
59
60   for(int i = 1; i < v; ++i)
61     {
62       if(  issolid(pbase->x + 1, pbase->y + i*16))
63         return true;
64     }
65   for(int i = 1; i < v; ++i)
66     {
67       if(  issolid(pbase->x + pbase->width - 1, pbase->y + i*16))
68         return true;
69     }
70
71   return false;
72 }
73
74
75 void collision_swept_object_map(base_type* old, base_type* current)
76 {
77   int steps; /* Used to speed up the collision tests, by stepping every 16pixels in the path. */
78   int h;
79   float lpath; /* Holds the longest path, which is either in X or Y direction. */
80   float xd,yd; /* Hold the smallest steps in X and Y directions. */
81   float temp, xt, yt; /* Temporary variable. */
82
83   lpath = 0;
84   xd = 0;
85   yd = 0;
86
87   if(old->x == current->x && old->y == current->y)
88     {
89       return;
90     }
91   else if(old->x == current->x && old->y != current->y)
92     {
93       lpath = current->y - old->y;
94       if(lpath < 0)
95         {
96           yd = -1;
97           lpath = -lpath;
98         }
99       else
100         {
101           yd = 1;
102         }
103
104       h = 1;
105       xd = 0;
106     }
107   else if(old->x != current->x && old->y == current->y)
108     {
109       lpath = current->x - old->x;
110       if(lpath < 0)
111         {
112           xd = -1;
113           lpath = -lpath;
114         }
115       else
116         {
117           xd = 1;
118         }
119       h = 2;
120       yd = 0;
121     }
122   else
123     {
124       lpath = current->x - old->x;
125       if(lpath < 0)
126         lpath = -lpath;
127       if(current->y - old->y > lpath || old->y - current->y > lpath)
128         lpath = current->y - old->y;
129       if(lpath < 0)
130         lpath = -lpath;
131       h = 3;
132       xd = (current->x - old->x) / lpath;
133       yd = (current->y - old->y) / lpath;
134     }
135
136   steps = (int)(lpath / (float)16);
137
138   old->x += xd;
139   old->y += yd;
140
141   for(float i = 0; i <= lpath; old->x += xd, old->y += yd, ++i)
142     {
143       if(steps > 0)
144         {
145           old->y += yd*16.;
146           old->x += xd*16.;
147           steps--;
148         }
149
150       if(collision_object_map(old))
151         {
152           switch(h)
153             {
154             case 1:
155               current->y = old->y - yd;
156               while(collision_object_map(current))
157                 current->y -= yd;
158               break;
159             case 2:
160               current->x = old->x - xd;
161               while(collision_object_map(current))
162                 current->x -= xd;
163               break;
164             case 3:
165               xt = current->x;
166               yt = current->y;
167               current->x = old->x - xd;
168               current->y = old->y - yd;
169               while(collision_object_map(current))
170                 {
171                   current->x -= xd;
172                   current->y -= yd;
173                 }
174
175               temp = current->x;
176               current->x = xt;
177               if(!collision_object_map(current))
178                 break;
179               current->x = temp;
180               temp = current->y;
181               current->y = yt;
182
183               if(!collision_object_map(current))
184                 {
185                   break;
186                 }
187               else
188                 {
189                   current->y = temp;
190                   while(!collision_object_map(current))
191                     current->y += yd;
192                   current->y -= yd;
193                   break;
194                 }
195
196               break;
197             default:
198               break;
199             }
200           break;
201         }
202     }
203
204   *old = *current;
205 }
206
207
208 Tile* gettile(float x, float y)
209 {
210   return TileManager::instance()->get(World::current()->get_level()->gettileid(x, y));
211 }
212
213 bool issolid(float x, float y)
214 {
215   Tile* tile = gettile(x,y);
216   return tile && tile->solid;
217 }
218
219 bool isbrick(float x, float y)
220 {
221   Tile* tile = gettile(x,y);
222   return tile && tile->brick;
223 }
224
225 bool isice(float x, float y)
226 {
227   Tile* tile = gettile(x,y);
228   return tile && tile->ice;
229 }
230
231 bool isfullbox(float x, float y)
232 {
233   Tile* tile = gettile(x,y);
234   return tile && tile->fullbox;
235 }
236
237 bool isdistro(float x, float y)
238 {
239   Tile* tile = gettile(x,y);
240   return tile && tile->distro;
241 }
242
243 /* EOF */
244
245