furhter improve collision detection by reintroducing time of collision, still more...
[supertux.git] / lib / special / collision.cpp
1 #include <config.h>
2
3 #include "collision.h"
4
5 #include <algorithm>
6 #include <iostream>
7 #include <stdio.h>
8 #include <float.h>
9 #include <math.h>
10 #include "math/vector.h"
11 #include "math/aatriangle.h"
12 #include "math/rectangle.h"
13 #include "collision_hit.h"
14
15 namespace SuperTux
16 {
17
18 static const float DELTA = .0001;
19
20 bool
21 Collision::rectangle_rectangle(CollisionHit& hit, const Rectangle& r1,
22     const Vector& movement, const Rectangle& r2)
23 {
24   if(r1.p2.x < r2.p1.x || r1.p1.x > r2.p2.x)
25     return false;
26   if(r1.p2.y < r2.p1.y || r1.p1.y > r2.p2.y)
27     return false;
28
29   if(movement.x > DELTA) {
30     hit.depth = r1.p2.x - r2.p1.x;
31     hit.time = hit.depth / movement.x;
32     hit.normal.x = -1;
33     hit.normal.y = 0;
34   } else if(movement.x < -DELTA) {
35     hit.depth = r2.p2.x - r1.p1.x;
36     hit.time = hit.depth / -movement.x;
37     hit.normal.x = 1;
38     hit.normal.y = 0;
39   } else {
40     if(movement.y > -DELTA && movement.y < DELTA) {
41       return false;
42     }
43     hit.time = FLT_MAX;
44   }
45
46   if(movement.y > DELTA) {
47     float ydepth = r1.p2.y - r2.p1.y;
48     float yt = ydepth / movement.y;
49     if(yt < hit.time) {
50       hit.depth = ydepth;
51       hit.time = yt;
52       hit.normal.x = 0;
53       hit.normal.y = -1;
54     }
55   } else if(movement.y < -DELTA) {
56     float ydepth = r2.p2.y - r1.p1.y;
57     float yt = ydepth / -movement.y;
58     if(yt < hit.time) {
59       hit.depth = ydepth;
60       hit.time = yt;
61       hit.normal.x = 0;
62       hit.normal.y = 1;
63     }
64   }
65
66   return true;
67 }
68
69 //---------------------------------------------------------------------------
70
71 static void makePlane(const Vector& p1, const Vector& p2, Vector& n, float& c)
72 {
73   n = Vector(p2.y-p1.y, p1.x-p2.x);
74   c = -(p2 * n);
75   float nval = n.norm();             
76   n /= nval;
77   c /= nval;
78 }
79
80 bool
81 Collision::rectangle_aatriangle(CollisionHit& hit, const Rectangle& rect,
82     const Vector& movement, const AATriangle& triangle)
83 {
84   if(!rectangle_rectangle(hit, rect, movement, (const Rectangle&) triangle))
85     return false;
86   
87   Vector normal;
88   float c;
89   Vector p1;
90   switch(triangle.dir) {
91     case AATriangle::SOUTHWEST:
92       p1 = Vector(rect.p1.x, rect.p2.y);
93       makePlane(triangle.p1, triangle.p2, normal, c);
94       break;
95     case AATriangle::NORTHEAST:
96       p1 = Vector(rect.p2.x, rect.p1.y);
97       makePlane(triangle.p2, triangle.p1, normal, c);
98       break;
99     case AATriangle::SOUTHEAST:
100       p1 = rect.p2;
101       makePlane(Vector(triangle.p1.x, triangle.p2.y),
102           Vector(triangle.p2.x, triangle.p1.y), normal, c);
103       break;
104     case AATriangle::NORTHWEST:
105       p1 = rect.p1;
106       makePlane(Vector(triangle.p2.x, triangle.p1.y),
107           Vector(triangle.p1.x, triangle.p2.y), normal, c);
108       break;
109   }
110
111   float depth = -(normal * p1) - c;
112   if(depth < 0)
113     return false;
114   if(depth < hit.depth) {
115     hit.depth = depth;
116     hit.normal = normal;
117   }
118
119   return true;
120 }
121
122 }