4 // Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
22 #include "collision.h"
35 bool rectcollision(const base_type& one, const base_type& two)
37 return (one.x >= two.x - one.width + 1 &&
38 one.x <= two.x + two.width - 1 &&
39 one.y >= two.y - one.height + 1 &&
40 one.y <= two.y + two.height - 1);
43 bool rectcollision_offset(const base_type& one, const base_type& two, float off_x, float off_y)
45 return (one.x >= two.x - one.width + off_x + 1 &&
46 one.x <= two.x + two.width + off_x - 1 &&
47 one.y >= two.y - one.height + off_y + 1 &&
48 one.y <= two.y + two.height + off_y - 1);
51 bool collision_object_map(const base_type& base)
53 const TileMap& tilemap = *Sector::current()->solids;
55 // we make the collision rectangle 1 pixel smaller
56 int starttilex = int(base.x+1) / 32;
57 int starttiley = int(base.y+1) / 32;
58 int max_x = int(base.x + base.width);
59 int max_y = int(base.y + base.height);
63 for(int x = starttilex; x*32 < max_x; ++x) {
64 for(int y = starttiley; y*32 < max_y; ++y) {
65 Tile* tile = tilemap.get_tile(x, y);
66 if(tile && tile->attributes & Tile::SOLID)
79 void* collision_func(const base_type& base, tiletestfunction function)
81 const TileMap& tilemap = *Sector::current()->solids;
83 int starttilex = int(base.x) / 32;
84 int starttiley = int(base.y) / 32;
85 int max_x = int(base.x + base.width);
86 int max_y = int(base.y + base.height);
88 for(int x = starttilex; x*32 < max_x; ++x) {
89 for(int y = starttiley; y*32 < max_y; ++y) {
90 Tile* tile = tilemap.get_tile(x, y);
91 void* result = function(tile);
100 static void* test_goal_tile_function(Tile* tile)
102 if(tile && (tile->attributes & Tile::GOAL))
107 Tile* collision_goal(const base_type& base)
109 return (Tile*) collision_func(base, test_goal_tile_function);
112 void collision_swept_object_map(base_type* old, base_type* current)
114 int steps; /* Used to speed up the collision tests, by stepping every 16pixels in the path. */
116 float lpath; /* Holds the longest path, which is either in X or Y direction. */
117 float xd,yd; /* Hold the smallest steps in X and Y directions. */
118 float temp, xt, yt; /* Temporary variable. */
124 if(old->x == current->x && old->y == current->y)
128 else if(old->x == current->x && old->y != current->y)
130 lpath = current->y - old->y;
144 else if(old->x != current->x && old->y == current->y)
146 lpath = current->x - old->x;
161 lpath = current->x - old->x;
164 if(current->y - old->y > lpath || old->y - current->y > lpath)
165 lpath = current->y - old->y;
169 xd = (current->x - old->x) / lpath;
170 yd = (current->y - old->y) / lpath;
173 steps = (int)(lpath / (float)16);
175 float orig_x = old->x;
176 float orig_y = old->y;
180 for(float i = 0; i <= lpath; old->x += xd, old->y += yd, ++i)
189 if(collision_object_map(*old))
191 if(tileinfo.tile->slope_angle != 0)
192 { // in case this is a slope, set the right Y position
194 if(tileinfo.tile->slope_angle > 0 && tileinfo.tile->slope_angle < M_PI/2)
195 current->y = tileinfo.y - current->height +
196 (tileinfo.x - current->x)*tan(M_PI/2 - tileinfo.tile->slope_angle)
199 if(tileinfo.tile->slope_angle > M_PI/2 && tileinfo.tile->slope_angle < M_PI)
200 current->y = tileinfo.y - current->height +
201 (current->x - tileinfo.x)*tan(M_PI - tileinfo.tile->slope_angle)
209 current->y = old->y - yd;
210 while(collision_object_map(*current))
214 current->x = old->x - xd;
215 while(collision_object_map(*current))
221 current->x = old->x - xd;
222 current->y = old->y - yd;
223 while(collision_object_map(*current))
231 if(!collision_object_map(*current))
237 if(!collision_object_map(*current))
244 while(!collision_object_map(*current))
259 if((xd > 0 && current->x < orig_x) || (xd < 0 && current->x > orig_x))
261 if((yd > 0 && current->y < orig_y) || (yd < 0 && current->y > orig_y))
267 Tile* gettile(float x, float y)
269 const TileMap& tilemap = *Sector::current()->solids;
270 return tilemap.get_tile_at(Vector(x, y));
273 bool issolid(float x, float y)
275 Tile* tile = gettile(x,y);
276 return tile && (tile->attributes & Tile::SOLID);
279 bool isbrick(float x, float y)
281 Tile* tile = gettile(x,y);
282 return tile && (tile->attributes & Tile::BRICK);
285 bool isice(float x, float y)
287 Tile* tile = gettile(x,y);
288 return tile && (tile->attributes & Tile::ICE);
291 bool isspike(float x, float y)
293 Tile* tile = gettile(x,y);
294 return tile && (tile->attributes & Tile::SPIKE);
297 bool isfullbox(float x, float y)
299 Tile* tile = gettile(x,y);
300 return tile && (tile->attributes & Tile::FULLBOX);
303 bool iscoin(float x, float y)
305 Tile* tile = gettile(x,y);
306 return tile && (tile->attributes & Tile::COIN);