2D物理引擎碰撞响应对象的旋转

时间:2012-07-25 17:07:31

标签: 2d game-engine

我正在编写自己的基本物理引擎,现在我遇到了一个我无法解决的问题。可能是因为我不知道如何谷歌这个问题。

所以这是我的问题。我希望这张图片可以解释它:

Collision response

我有两个对象。灰色的是固定的,不移动,绿色的是从顶部落下的。 绿色物体有三个向量:力,加速度和速度。它与固定的灰色物体碰撞。

真正的问题是如何在绿色物体掉落时获得旋转?

2 个答案:

答案 0 :(得分:9)

听起来你可能没有理解刚体动力学的基础物理学。我之所以这么说,只是因为在谈到这类问题时你没有提到常用的任何术语。您需要向系统中的每个动态体引入方向和角速度(位置和线速度的旋转模拟)的概念,并计算各种中间量,如惯性矩,角加速度和扭矩。 / p>

对于Game Developer Magazine来说,也许最好的介绍性参考是Chris Hecker's series篇文章。假设你已经有非旋转动力学(在第1部分中介绍)和碰撞检测(本系列未涵盖)解决了,你应该从第2部分开始并进入第3部分。它们将为你提供物理学的坚实基础和实现旋转碰撞响应所必需的数学。

答案 1 :(得分:8)

当对象发生碰撞时,您将如下所述进行一次。

让我们将绿色矩形称为“a”,将另一个称为“b”。

1

首先你需要矩形“旋转质量”,惯性质量。

a.i = 4/3 *宽度*高度*(宽度^ 2 +高度^ 2)* a.density

2

然后你需要从矩形的质心(所有角落的平均位置)指向接触位置(矩形碰撞的位置)的矢量,让我们称之为“r”。

3

然后你需要找到碰撞正常。该法线是从b施加的脉冲的方向。法线是长度为1个单位的向量。在你的例子中,法线可能会指向上方。让我们称法线向量“n”。

4

现在你将需要一个接触点的速度。如果a不旋转,则公式为:

vp = a.vel

如果a正在旋转,则公式为:

vp = a.vel + cross(a.r_vel,r)

a.r_vel是以弧度给出的旋转速度,正方向是逆时针。

cross()表示交叉产品,功能是:

交叉(v,i)= [-i * v.y,i * v.x]

扩展后的公式为:

vp = a.v + [-r * a.r_vel.y,r * a.r_vel.x]

5

现在您需要计算对象是否朝向彼此移动。将vp投影到n。

vp_p = dot(vp,n)

dot(v1,v2)= v1.x * v2.x + v1.y * v2.y

vp_p是标量(值,不是矢量)。

如果vp_p为负,则对象将朝向彼此移动,如果它是> 0他们正在分开。

6

现在你需要计算阻止a进入b的冲动,冲动是:

j = -vp_p /(                 1 / a.mass + cross(r,n)^ 2 / a.i.             )

两个向量之间的叉积是:

cross(v1,v2)= v1.x * v2.y - v1.y * v2.x

返回一个标量。

将脉冲与法线相乘得到脉冲矢量:

jn = j * n

7

现在你需要将冲动应用于:

a.new_vel = a.old_vel + jn / a.mass;

a.new_r_vel = a.old_r_vel + cross(r,jn)/ a.i;

如果你想让碰撞完全弹性,你必须将脉冲乘以2.让我们将这个乘数称为“e”。 e需要在1和2之间.1表示没有能量守恒,2表示所有能量都是守恒的。

示例代码:

var vp = a.vel + cross(a.r_vel, r);
var vp_p = dot(vp,n); // negative val = moving towards each other
if (vp_p >= 0) { // do they move apart?
    return false;
}

// normal impulse
var j = - e * vp_p / (
            1/a.mass + cross(r,n)^2 / a.i
        );
var jn = j * n;
//
a.vel = a.vel + jn / a.mass;
a.r_vel = a.r_vel + cross(r,jn) / a.i;

如果b不是静态的,算法会略有不同:

a.r =从质心指向接触位置的矢量

var vp = a.vel + cross(a.r_vel, a.r) - b.vel - cross(b.r_vel, b.r);
var vp_p = dot(vp,n); // negative val = moving towards each other
if (vp_p >= 0) { // do they move apart?
    return false;
}

// normal impulse
var j = - e * vp_p / (
            1/a.mass + cross(a.r,n)^2 / a.i +
            1/b.mass + cross(b.r,n)^2 / b.i
        );
var jn = j * n;
//
a.vel = a.vel + jp / a.mass;
a.r_vel = a.r_vel + cross(a.r,jn) / a.i;
b.vel = b.vel - jp / b.mass;
b.r_vel = b.r_vel - cross(b.r,jn) / b.i;

公式如何工作/来源:

http://www.myphysicslab.com/collision.html#resting_contact