我正在2D游戏中构建一些碰撞检测,我有一种方法来测试碰撞并找到碰撞的深度和法线,但我一直在努力弄清楚碰撞发生在哪一边。
此处的CirclePosition和RectPosition是形状的中心。我使用OpenGL,所以正Y=向下,负Y=向上。
我测试的对象是一个圆和一个正方形。这些形状是轴对齐的。
所以我的问题是:
如何检测圆击中了正方形的哪一边
这是我迄今为止的代码:
enum side {
SideLeft,
SideRight,
SideAbove,
SideBelow,
};
typedef struct {
int Collided;
float Depth;
float2 Normal;
side Side;
} collision;
collision CircleRectIntersection(float2 CirclePosition, float Radius, float2 RectPosition, float2 Size) {
float Top = RectPosition.Y - (Size.Y / 2);
float Left = RectPosition.X - (Size.X / 2);
float Bottom = RectPosition.Y + (Size.Y / 2);
float Right = RectPosition.X + (Size.X / 2);
float ExtentX = Size.X / 2;
float ExtentY = Size.Y / 2;
float2 N = RectPosition - CirclePosition;
float2 Closest = N;
Closest.X = Clamp(-ExtentX, ExtentX, Closest.X);
Closest.Y = Clamp(-ExtentY, ExtentY, Closest.Y);
bool Inside = false;
if(N == Closest) {
Inside = true;
if(fabs(N.X) > fabs(N.Y)) {
if(Closest.X > 0) Closest.X = ExtentX;
else Closest.X = -ExtentX;
}
else {
if(Closest.Y > 0) Closest.Y = ExtentY;
else Closest.Y = -ExtentY;
}
}
float2 Normal = N - Closest;
float D = LengthSquare(Normal);
float R = Radius;
D = sqrt(D);
collision C;
if(D > R && !Inside) {
C.Collided = 0;
return C;
}
if(Inside) C.Normal = -N;
else C.Normal = N;
C.Depth = R - D;
return C;
}
下面是一些我希望它如何工作的示例代码:
int main(int argc, char **argv) {
float2 RectPosition = float2(100, 100);
float2 RectSize = float2(100, 100);
float2 CirclePosition = float2(150, 100);
float2 Radius = 20.0f;
collision C = CircleRectIntersection(CirclePosition, Radius, RectPosition, RectSize);
// here I would expect C.Side to be side.Right, as the circle is to the right of the rect
}
四个距离中最小的一个,即从CirclePosition.X
到{Left,Right}的两个距离和从CirclePosition.Y
到{Top,Bottom}的二个距离,将告诉您矩形的哪一侧被击中。