我想在圆圈和圆环部分之间进行碰撞检测。圆圈由position
位置定义,radius
。另一个对象由inner
和outer
半径定义,然后是startPoint
和endPoint
两个[x,y]点。
在下面的示例中,this
是圆圈,other
是圆环部分。
首先,我只是检查它是否与完整的环相撞。这没有问题。
float mag = this.position.Magnitude();
if (mag < other.InnerRadius() - this.radius ||
mag > other.OuterRadius() + this.radius) {
return false;
}
但是我需要检查圆圈是在两点定义的部分的内部还是外部。我能得到的最近的是检查它是否没有与起始和结束向量发生碰撞,但是当圆圈完全位于环形部分内部时,这会返回错误的结果。
auto dot1 = Vector::Dot(position, other.StartPoint());
auto projected1 = dot1 / Vector::Dot(other.StartPoint(), other.StartPoint()) * other.StartPoint();
auto distance1 = Vector::Distance(position, projected1);
auto dot2 = Vector::Dot(position, other.EndPoint());
auto projected2 = dot2 / Vector::Dot(other.EndPoint(), other.EndPoint()) * other.EndPoint();
auto distance2 = Vector::Distance(position, projected2);
return distance1 < radius || distance2 < radius;
检查圆是否与这两个向量定义的对象发生碰撞的最简单方法是什么?
编辑:我在这里使用的所有点对象都是我的自定义Vector
类,它已经实现了所有向量操作。
Edit2:只是为了澄清,环形对象的起源是[0,0]
答案 0 :(得分:2)
这是一个简单的算法。
首先,我们同意变量名称:
此处r1 ≤ r2
,-π/2 ≤ a1 ≤ a2 ≤ π/2
。
(正如我在评论中提醒的那样,你有起点和终点而不是角度,但我会使用角度,因为它们看起来更方便。你可以通过atan2(y-ry, x-rx)
从点轻松获得角度,确保a1 ≤ a2
。或者你可以重写算法,根本不使用角度。)
我们需要考虑3种不同的情况。案例取决于圆心相对于环段的位置:
在第一种情况下,如您所知,如果向量(cx-rx, cy-ry)
的长度大于r1-rc
且小于r2+rc
,则会发生冲突。
在第二种情况下,如果圆心和最近直边之间的距离小于rc
,则会发生碰撞。
在第3种情况下,如果圆心与最近的4个角之间的距离小于rc
,则会发生碰撞。
这是一些伪代码:
rpos = vec2(rx,ry); // Ring segment center coordinates
cpos = vec2(cx,cy); // Circle coordinates
a = atan2(cy-ry, cx-rx); // Relative angle
r = length(cpos - rpos); // Distance between centers
if (a > a1 && a < a2) // Case 1
{
does_collide = (r+rc > a1 && r-rc < a2);
}
else
{
// Ring segment corners:
p11 = vec2(cos(a1), sin(a1)) * r1;
p12 = vec2(cos(a1), sin(a1)) * r2;
p21 = vec2(cos(a2), sin(a2)) * r1;
p22 = vec2(cos(a2), sin(a2)) * r2;
if (((cpos-p11) · (p12-p11) > 0 && (cpos-p12) · (p11-p12) > 0) ||
((cpos-p21) · (p22-p21) > 0 && (cpos-p22) · (p21-p22) > 0)) // Case 2
{
// Normals of straight edges:
n1 = normalize(vec2(p12.y - p11.y, p11.x - p12.x));
n2 = normalize(vec2(p21.y - p22.y, p22.x - p21.x));
// Distances to edges:
d1 = n1 · (cpos - p11);
d2 = n2 · (cpos - p21);
does_collide = (min(d1, d2) < rc);
}
else // Case 3
{
// Squared distances to corners
c1 = length_sqr(cpos-p11);
c2 = length_sqr(cpos-p12);
c3 = length_sqr(cpos-p21);
c4 = length_sqr(cpos-p22);
does_collide = (sqrt(min(c1, c2, c3, c4)) < rc);
}
}
答案 1 :(得分:0)
将小圆圈与光线进行比较:
首先检查圆圈是否包含原点;如果是,则它与光线相交。否则,请继续阅读。
考虑从原点到圆心的矢量v。将其标准化,将光线R标准化,并取得叉积Rxv。如果它为正,则v从R逆时针方向移动,否则从R方向顺时针方向移动。无论哪种方式,取acos得到它们之间的角度。
如果圆的半径为r且其中心距原点的距离为d,则圆的角半宽(从原点看)为asin(r / d)。如果R和v之间的角度小于该角度,则圆与光线相交。
假设您知道对象是从开始到结束顺时针还是逆时针延伸。 (这些数字不会告诉你,你必须已经知道它或问题是无法解决的。)在你的例子中,顺时针方向。现在你必须要小心;如果弧的角度长度<= pi,则可以继续,否则更容易确定圆是否在对象扇区的外的较小扇区中。但是假设物体的跨度小于pi,则圆圈位于物体的扇区内(即光线之间),当且仅当它从开始顺时针方向并且从末端逆时针方向开始。