summaryrefslogtreecommitdiff
path: root/src/game-server/collisiondetection.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/game-server/collisiondetection.cpp')
-rw-r--r--src/game-server/collisiondetection.cpp138
1 files changed, 132 insertions, 6 deletions
diff --git a/src/game-server/collisiondetection.cpp b/src/game-server/collisiondetection.cpp
index 8fdd50e5..6297e3d6 100644
--- a/src/game-server/collisiondetection.cpp
+++ b/src/game-server/collisiondetection.cpp
@@ -17,26 +17,27 @@
* with The Mana World; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * $Id: being.cpp 3010 2007-01-05 20:12:51Z gmelquio $
+ * $Id: $
*/
#include "collisiondetection.hpp"
-#include "point.h"
-
#include <cmath>
-#include "utils/fastsqrt.h"
+
+#include "point.h"
+#include "utils/mathutils.h"
bool
Collision::circleWithCirclesector( const Point& circlePos, int circleRadius,
- const Point& secPos, int secRadius, float secAngle, float secSize)
+ const Point& secPos, int secRadius,
+ float secAngle, float secSize)
{
float targetAngle;
//calculate distance
int distX = circlePos.x - secPos.x;
int distY = circlePos.y - secPos.y;
- float invDist = fastInvSqrt(distX * distX + distY * distY);
+ float invDist = utils::math::fastInvSqrt(distX * distX + distY * distY);
float dist = 1.0f / invDist;
//if out of range we can't hit it
@@ -75,3 +76,128 @@ Collision::circleWithCirclesector( const Point& circlePos, int circleRadius,
return (targetDiff < secSize * 0.5f);
}
+
+/**
+ * Collision of a Disk with a Circle-Sector
+ *
+ * For a detailled explanation of this function please see:
+ * http://wiki.themanaworld.org/index.php/Collision_determination
+ */
+bool
+Collision::diskWithCircleSector(const Point &diskCenter, int diskRadius,
+ const Point &sectorCenter, int sectorRadius,
+ int halfTopAngle, int placeAngle)
+{
+ //The coordinates of the diskcenter the base coordinate systems and an
+ //alternate coordinate system
+ float Px, Py, Px1, Py1,
+ distAx, distAy, distBx, distBy;
+
+ //Converting the radii to float
+ float R = (float) sectorRadius;
+ float Rp = (float) diskRadius;
+
+ //The values of the trigonomic functions (only have to be computed once)
+ float sinAlpha, cosAlpha, sinBeta, cosBeta, tan2Alpha;
+
+ //Transform to the primary coordinate system
+ Px = diskCenter.x - sectorCenter.x;
+ Py = diskCenter.y - sectorCenter.y;
+
+ //Calculating the values of the trigonomic functions
+ sinAlpha = utils::math::cachedSin(halfTopAngle);
+ cosAlpha = utils::math::cachedCos(halfTopAngle);
+ sinBeta = utils::math::cachedSin(placeAngle);
+ cosBeta = utils::math::cachedCos(placeAngle);
+
+ /**
+ * This bounding circle implementation can be used up and until a
+ * half-top-angle of +/- 85 degrees. The bounding circle becomes
+ * infinitly large at 90 degrees. Above about 60 degrees a bounding
+ * half-circle with radius R becomes more efficient.
+ * (The additional check for a region 1 collision can then be scrapped.)
+ */
+
+ // Calculating the coordinates of the disk's center in coordinate system 4
+ Px1 = Px * cosBeta + Py * sinBeta;
+ Py1 = Py * cosBeta - Px * sinBeta;
+
+ //Check for an intersection with the bounding circle
+ // (>) : touching is accepted
+ if ((cosAlpha * Px1 * Px1 + cosAlpha * Py1 * Py1 - Px1 * R)
+ > (Rp * Rp * cosAlpha + Rp * R)) return false;
+
+ //Check for a region 4 collision
+ if ((Px*Px + Py*Py) <= (Rp*Rp)) return true;
+
+ //Calculating the coordinates of the disk's center in coordinate system 1
+ Px1 = Px * (cosAlpha * cosBeta + sinAlpha * sinBeta)
+ + Py * (cosAlpha * sinBeta - sinAlpha * cosBeta);
+ Py1 = Py * (cosAlpha * cosBeta + sinAlpha * sinBeta)
+ - Px * (cosAlpha * sinBeta - sinAlpha * cosBeta);
+
+ //Check if P is in region 5 (using coordinate system 1)
+ if ((Px1 >= 0.0f) && (Px1 <= R) && (Py1 <= 0.0f))
+ {
+ //Return true on intersection, false otherwise
+ // (>=) : touching is accepted
+ return (Py1 >= -1.0f * Rp);
+ }
+
+ //Check if P is in region 3 (using coordinate system 1)
+ if ((Px1 > R) && (Py1 <= 0.0f))
+ {
+ //Calculating the vector from point A to the disk center
+ distAx = Px - R * (cosAlpha*cosBeta + sinAlpha*sinBeta);
+ distAy = Py - R * (cosAlpha*sinBeta - sinAlpha*cosBeta);
+
+ //Check for a region 3 collision
+ return ((distAx*distAx + distAy*distAy) <= Rp*Rp);
+ }
+
+ //Discard, if P is in region 4 (was previously checked)
+ if ((Px1 < 0.0f) && (Py1 <= 0.0f)) return false;
+
+ tan2Alpha = utils::math::cachedTan(2 * halfTopAngle);
+
+ //Check if P is in region 1 (using coordinate system 1)
+ if ((Px1 >= 0.0f) && (Py1 >= 0.0f) && (Py1 <= Px1 * tan2Alpha))
+ {
+ //Return true on intersection, false otherwise
+ // (<=) : touching is accepted
+ return ((Px*Px + Py*Py) <= (R*R + Rp*Rp + 2.0f*R*Rp));
+ }
+
+ //Calculating the coordinates of the disk's center in coordinate system 3
+ Px1 = Px * (cosAlpha * cosBeta - sinAlpha * sinBeta)
+ + Py * (sinAlpha * cosBeta + cosAlpha * sinBeta);
+ Py1 = Py * (cosAlpha * cosBeta - sinAlpha * sinBeta)
+ - Px * (sinAlpha * cosBeta + cosAlpha * sinBeta);
+
+ //Discard, if P is in region 4 (was previously checked)
+ if ((Px1 < 0.0f) && (Py1 >= 0.0f)) return false;
+
+ //Check if P is in region 6 (using coordinate system 3)
+ if ((Px1 >= 0.0f) && (Px1 <= R) && (Py1 >= 0.0f))
+ {
+ //Return true on intersection, false otherwise
+ // (<=) : touching is accepted
+ return (Py1 <= Rp);
+ }
+
+ //Check if P is in region 2 (using coordinate system 3)
+ if ((Px1 > R) && (Py1 <= 0.0f))
+ {
+ //Calculating the vector from point B to the disk center
+ distBx = Px - R * (cosAlpha*cosBeta - sinAlpha*sinBeta);
+ distBy = Py - R * (cosAlpha*sinBeta + sinAlpha*cosBeta);
+
+ //Check for a region 2 collision
+ return ((distBx*distBx + distBy*distBy) <= (Rp*Rp));
+ }
+
+ // The intersection with the bounding circle is in region 4,
+ // but the disk and circle sector don't intersect.
+ return false;
+}
+