繁体   English   中英

与复合对象的圆碰撞

[英]Circle collision with compound object

我想在圆环的圆和截面之间进行碰撞检测。 由它定义圆的position位置和它的radius 另一个对象由inner半径和outer半径定义,然后由两个[x,y]点的一个startPointendPoint定义。

在下面的示例中, 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]

这是一个简单的算法。

首先,让我们在变量名上达成一致:

喵

这里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);
    }
}

要将小圆圈与射线进行比较:

首先检查圆是否包含原点; 如果是这样,则它与射线相交。 否则,请继续阅读。

考虑从圆的原点到圆心的向量v。 归一化,归一化射线R,并取叉积Rxv。 如果为正,则v从R逆时针旋转,否则从R顺时针旋转。两种方式都取acos来获得它们之间的角度。

如果圆的半径为r,并且圆心距原点的距离为d,则圆的角半角宽度(从原点看)为asin(r / d)。 如果R和v之间的角度小于该角度,则圆与射线相交。

假定您知道对象是从开始到结束顺时针还是逆时针延伸。 (数字不会告诉您,您必须已经知道,否则问题将无法解决。)在您的示例中,它是顺时针的。 现在您必须要小心; 如果圆弧的角长度小于或等于pi,则可以继续操作,否则可以更轻松地确定圆是否位于对象扇形之外的较小扇形中。 但是,假设对象的跨度小于pi,则当且仅当从起点开始是顺时针方向并且从终点开始是逆时针方向时,圆才在对象的扇区内(即射线之间)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM