JavaScript - 分离轴定理 - 碰撞检测有效,但响应无效?

11

现在,我正在尝试将响应应用于我的SAT、Circle - Poly和Poly - Poly碰撞检测。我将这篇文章中的代码移植到了JavaScript中:

http://rocketmandevelopment.com/blog/separation-of-axis-theorem-for-collision-detection/

现在,检测可以应用于所有类型,但响应失败了,并以疯狂的速度和错误的角度进行运动,它不依赖于对象的质量(使用面积平方而不是质量)且角速度未被应用。

JSFiddle(模拟中未应用重力,请使用箭头键移动),JS中的第一部分是向量,然后是物理学,最后是主函数。

这是我对形状的定义:(为“JSFiddle”链接添加了一些代码:P)

var Circle = function(body, c, r, cor, cof) {
    this.body = body // Static or dynamic
    this.c = c; // Center
    this.r = r; // Radius
    this.m = getCMass(r); // Mass = Area
    this.v = new Vector(); // Velocity
    this.cor = cor; // Coefficient of restitution
    this.cof = cof; // Coefficient of friction
    this.a = 0; // Angle
    this.av = 0; // Angular velocity
    this.type = "Circle";
}

var Polygon = function(body, c, vs, cor, cof) {
    this.body = body // Static or dynamic
    this.c = c; // Center
    this.vs = vs; // Vertices
    this.m = getPMass(vs); // Mass = Area
    this.v = new Vector(); // Velocity
    this.cor = cor; // Coefficient of restitution
    this.cof = cof; // Coefficient of friction
    this.a = 0; // Angle
    this.av = 0; // Angular velocity
    this.type = "Polygon";
}

function getCMass(r) { // More like, getCArea
    return (r * r * Math.PI);
}

function getPMass(vs) {
    var area = 0;
    var j = vs.length - 1;

    for (var i = 0; i < vs.length; i++) {
        area += (vs[j].x + vs[i].x) * (vs[j].y - vs[i].y); 
        j = i;
    }

    return (area / 2);
}

所有碰撞函数都会给出失败的响应结果,因此一定存在某种连接。

回到角速度问题,我知道如何旋转多边形,但我想在碰撞后得到新的角速度:

px = x * cos(a) - y * sin(a); 
py = x * sin(a) + y * cos(a);

还有,我制作了一个很不错的物理模拟器,可以模拟线条和贝塞尔曲线,这可能会有所帮助:http://murplyx.net/projects/csb/

对我来说最重要的部分是如何修复速度根据速度和角度正确地进行计算的问题?(我使用向量而不是三角函数-.-)然后我可以考虑质量和角速度。谢谢。我避免使用Box2D盒子。

编辑:添加了计算面积^2以设置质量相等的函数。


270 - 200 = 70 (重复) O_o - underscore
O_o 我一开始有 470 点声望,270 + 200 = 470 :P - user2039981
1
干得好!你正在赚钱和销售 :) - underscore
1个回答

4
在圆圆碰撞函数getCCCol(a, b)中,您正在计算a.center - b.center,这是两个圆心之间的向量,然后通过一个标量来缩放它,该标量表示以圆心之间的向量为单位测量的两个圆的重叠部分。我无法理解这个向量应该表示什么,但它代表一种长度或一种定向面积。
update()中,如果发生碰撞,则将上述值添加到圆的速度中(如果它们没有固定)。添加速度和长度(或面积)没有意义。您真正想做的是根据对象的当前速度、它们之间的接触平面、它们的质量以及可能的弹性来改变对象的速度向量。这也可能需要倒着运行模拟一段时间,以消除由于固定时间步长而产生的物体重叠。因此,例如,对于两个完全弹性的相等质量的圆头碰撞,您只想反转速度向量,而不根据碰撞的几何形状添加任何内容。
对于getPCCol(p, c)getPPCol(a, b)也是同样的情况,在这里您再次计算某种距离,在发生碰撞的情况下将其添加到速度中。这些值的目的是什么?
最后,我无法指出可以解决问题的任何单个问题。在发生碰撞的情况下更新速度的代码与该过程背后的物理学不匹配。我还真诚建议明确引入时间步长,因为您的位置更新步骤position = position + velocity确实应该是position = position + velocity x timestep。通过明确这一点,即使您选择一个时间步长,您也可以更轻松地检查计算的单位是否合理。
重新考虑如何执行模拟可能也是一个好主意。与其前进一个固定的时间步长,然后在发生碰撞的情况下回退 - 您目前没有这样做,但您可能迟早会这样做 - 不如先计算下一个碰撞的时间,然后仅将模拟推进到此点。现在,如果速度很快或对象足够小,则如果一个时间步长将对象沿着速度方向前进的距离大于所谓的碰撞伙伴的尺寸,则您的对象可以相互穿过。如果您正在模拟粒子并且碰撞不是(大)问题,则您的固定时间步长方法可能足够好,但如果您必须使用固定时间步长处理碰撞,则不太够好。
我希望这有所帮助,当然,如果有什么不清楚或需要进一步阐述,请随时问。
这是我可能尝试实现刚体动力学的方式,也就是我添加功能的顺序。每个步骤都只添加了一个或多个功能,但它们都比听起来要复杂得多。每个步骤都有数千页的研究和数十种甚至数百种实现选择。
  1. 没有角动量的粒子动力学

    通过简单的积分算法,定义具有质量、(质心)位置和速度的粒子。模拟它们的运动并对作用于质心的力做出响应。

  2. 带有角动量的粒子动力学

    添加惯性张量和角速度。考虑使用四元数。实现对作用于任何点而非仅质心的力做出响应。

  3. 带有碰撞的刚体动力学

    实现一个预测碰撞时间和碰撞点的碰撞搜索算法。使用基于脉冲的接触模型计算碰撞响应。这可能需要引入时间步长细分。

  4. 带有摩擦的刚体动力学

    添加像科尔沃姆摩擦这样的简单摩擦模型。

  5. 添加重力和其他力场

    在此,您必须决定是否只想要一个恒定的重力或者您还想计算物体之间的重力。您可以在第一步后立即添加重力,因为它只是作用于质心的力,但由于随着两个物体越来越接近,重力力会变得无限大,整个模拟很容易爆炸,即您的物体以高速飞行。模拟重力和其他力场通常需要更高级的积分算法。一般而言,您会发现向模拟中添加更多功能通常会增加对积分算法的要求,并且您将获得不稳定性。


显然这就是我为什么问这个问题的原因 -.- - user2039981
你刚才说圆圈不需要时间,因为它已经完成了。在哪里完成了? - Daniel Brückner
不,为什么我要这么做呢?我知道它有效,好吧,现在我只需要多边形 - 多边形和多边形 - 圆形。 - user2039981
你好?赏金将在4小时后结束。 - user2039981
所有这些,然后你加上我不理解,你不能解释一下“如何”吗?一个答案意味着1个答案而不是1000个、100个或10个答案。 - user2039981
显示剩余32条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接