Created
August 7, 2024 04:17
-
-
Save greg-kennedy/e1942d8e4ba5c716264d2212741b498f to your computer and use it in GitHub Desktop.
Stashing some 2d collision routines here
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// AABB to AABB collision | |
// In case of a hit, the first object is pushed out | |
static int aabb_aabb(short *x, short *y, unsigned short w, unsigned short h, | |
short ox, short oy, unsigned short ow, unsigned short oh) | |
{ | |
// find protrusion into each side | |
int p_l = *x + w - ox; if (p_l <= 0) return 0; | |
int p_r = ox + ow - *x; if (p_r <= 0) return 0; | |
int p_u = *y + h - oy; if (p_u <= 0) return 0; | |
int p_d = oy + oh - *y; if (p_d <= 0) return 0; | |
// collision. use minimum dist (above) to figure out which edge to lock to | |
if (p_l <= p_r && p_l <= p_u && p_l <= p_d) | |
*x = ox - w; | |
else if (p_r <= p_u && p_r <= p_d) | |
*x = ox + ow; | |
else if (p_u <= p_d) | |
*y = oy - h; | |
else | |
*y = oy + oh; | |
return 1; | |
} | |
// Point to Circle collision | |
// In case of a hit, the first object is pushed out | |
static int point_circle(float *x, float *y, | |
float ox, float oy, unsigned short or) | |
{ | |
// check distance | |
float d_sqr = sqr(ox - *x) + sqr(oy - *y); | |
// too close? | |
if (d_sqr >= sqr(or)) return 0; | |
// determine angle of intrusion | |
float theta = atan2f(oy - *y, ox - *x); | |
// push first object away | |
*x = ox - or * cos(theta); | |
*y = oy - or * sin(theta); | |
return 1; | |
} | |
// Circle to Circle collision | |
// In case of a hit, the first object is pushed out | |
static int circle_circle(float *x, float *y, unsigned short r, | |
float ox, float oy, unsigned short or) | |
{ | |
return point_circle(x, y, ox, oy, r + or); | |
} | |
// Circle to AABB collision | |
// In case of a hit, the first object is pushed out | |
static int circle_aabb(float *x, float *y, unsigned short r, | |
float ox0, float oy0, float ox1, float oy1) | |
{ | |
// find protrusion into each side of an expanded square | |
float p_l = *x + r - ox0; if (p_l <= 0) return 0; | |
float p_r = ox1 + r - *x; if (p_r <= 0) return 0; | |
float p_u = *y + r - oy0; if (p_u <= 0) return 0; | |
float p_d = oy1 + r - *y; if (p_d <= 0) return 0; | |
// it's in the bounding square. | |
// based on the closest edges, test a corner, or don't | |
// collision. use minimum dist (above) to figure out which edge to lock to | |
if (p_l <= p_r && p_l <= p_u && p_l <= p_d) | |
{ | |
// left edge | |
if (*y < oy0) return point_circle(x, y, ox0, oy0, r); | |
else if (*y > oy1) return point_circle(x, y, ox0, oy1, r); | |
else *x = ox0 - r; | |
} else if (p_r <= p_u && p_r <= p_d) { | |
// right edge | |
if (*y < oy0) return point_circle(x, y, ox1, oy0, r); | |
else if (*y > oy1) return point_circle(x, y, ox1, oy1, r); | |
else *x = ox1 + r; | |
} else if (p_u <= p_d) { | |
// top edge | |
if (*x < ox0) return point_circle(x, y, ox0, oy0, r); | |
else if (*x > ox1) return point_circle(x, y, ox1, oy0, r); | |
else *y = oy0 - r; | |
} else { | |
// bottom edge | |
// top edge | |
if (*x < ox0) return point_circle(x, y, ox0, oy1, r); | |
else if (*x > ox1) return point_circle(x, y, ox1, oy1, r); | |
else *y = oy1 + r; | |
} | |
return 1; | |
} | |
// Ray to AABB collision | |
// Return a distance at which the collision happens (or t_start if never) | |
static float ray_aabb(float x0, float y0, float dx, float dy, | |
float ox0, float oy0, float ox1, float oy1) | |
{ | |
float tmin = -FLT_MAX; float tmax = FLT_MAX; | |
// float ray_dx = x1 - x0; | |
if (dx != 0.0) { | |
double tx1 = (ox0 - x0)/dx; | |
double tx2 = (ox1 - x0)/dx; | |
tmin = max(tmin, min(tx1, tx2)); | |
tmax = min(tmax, max(tx1, tx2)); | |
} | |
// float ray_dy = y1 - y0; | |
if (dy != 0.0) { | |
double ty1 = (oy0 - y0)/dy; | |
double ty2 = (oy1 - y0)/dy; | |
tmin = max(tmin, min(ty1, ty2)); | |
tmax = min(tmax, max(ty1, ty2)); | |
} | |
if (tmax >= tmin) return tmin; | |
else return FLT_MAX; | |
} | |
// Ray to Circle collision | |
// Return a distance at which the collision happens (or t_start if never) | |
static float ray_circle(float x0, float y0, float dx, float dy, | |
float ox, float oy, float or) | |
{ | |
// determine the | |
float tmin = -FLT_MAX; float tmax = FLT_MAX; | |
// float ray_dx = x1 - x0; | |
if (dx != 0.0) { | |
double tx1 = (ox0 - x0)/dx; | |
double tx2 = (ox1 - x0)/dx; | |
tmin = max(tmin, min(tx1, tx2)); | |
tmax = min(tmax, max(tx1, tx2)); | |
} | |
// float ray_dy = y1 - y0; | |
if (dy != 0.0) { | |
double ty1 = (oy0 - y0)/dy; | |
double ty2 = (oy1 - y0)/dy; | |
tmin = max(tmin, min(ty1, ty2)); | |
tmax = min(tmax, max(ty1, ty2)); | |
} | |
if (tmax >= tmin) return tmin; | |
else return FLT_MAX; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment