球与球碰撞 - 碰撞后速度显著增加

4

我用Objective-C实现了问题“Ball to Ball Collision - Detection and Handling”中的代码。然而,每当球以角度碰撞时,它们的速度会急剧增加。所有向量数学都是使用cocos2d-iphone完成的,其中包括CGPointExtension.h头文件。这种不希望的加速的原因是什么?

以下是速度增加的示例:

输入:
mass == 12.56637
velocity.x == 1.73199439
velocity.y == -10.5695238

ball.mass == 12.56637
ball.velocity.x == 6.04341078
ball.velocity.y == 14.2686739

输出:
mass == 12.56637
velocity.x == 110.004326
velocity.y == -10.5695238

球的质量为12.56637
球的速度x为-102.22892
球的速度y为-72.4030228

#import "CGPointExtension.h"
#define RESTITUTION_CONSTANT (0.75) //elasticity of the system

- (void) resolveCollision:(Ball*) ball
{
    // get the mtd (minimum translation distance)
    CGPoint delta = ccpSub(position, ball.position);
    float d = ccpLength(delta);
    // minimum translation distance to push balls apart after intersecting
    CGPoint mtd = ccpMult(delta, (((radius + ball.radius)-d)/d)); 


    // resolve intersection --
    // inverse mass quantities
    float im1 = 1 / [self mass]; 
    float im2 = 1 / [ball mass];

    // push-pull them apart based off their mass
    position = ccpAdd(position, ccpMult(mtd, (im1 / (im1 + im2))));
    ball.position = ccpSub(ball.position, ccpMult(mtd, (im2 / (im1 + im2))));

    // impact speed
    CGPoint v = ccpSub(velocity, ball.velocity);
    float vn = ccpDot(v,ccpNormalize(mtd));

    // sphere intersecting but moving away from each other already
    if (vn > 0.0f) return;

    // collision impulse
    float i = (-(1.0f + RESTITUTION_CONSTANT) * vn) / ([self mass] + [ball mass]);
    CGPoint impulse = ccpMult(mtd, i);


    // change in momentum
    velocity = ccpAdd(velocity, ccpMult(impulse, im1));
    ball.velocity = ccpSub(ball.velocity, ccpMult(impulse, im2));

}

你的物理学知识是问题所在:由于恢复系数为1.75(超过1),你设置了一个不保守动能的碰撞。因此,这不是一个程序相关错误。 - jpinto3912
你能发布一下最终版本的工作代码吗? - Cade Roux
@jpinto3912 - 你是不是指动量守恒? - Not Sure
@Cade Roux - 仍然没有起作用...使用真实的质量而不是反向的质量只会导致球互相推动,而不是以荒谬的速度弹开。 - Andrew Hundt
这是我编写的代码的最终版本的谷歌代码链接。当球直接叠在彼此上方时,我添加了一些特殊的除以零条件。http://code.google.com/p/simucal-projects/source/browse/ballbounce/trunk/Ball.java - mmcdole
我不确定。为什么不检查退化情况下的公式。两个相同的球(质量和半径相同),一个静止,COR = 1,球心与第二个移动球的轨迹在同一直线上。你应该看到移动球停止运动,第二个球开始以原始移动球的速度运动,就像牛顿摆动一样。 - Cade Roux
3个回答

5
经过查看原始代码和原始发布者的评论,代码似乎相同。因此,如果原始实现是正确的,则我会怀疑是向量库或某种未初始化变量的问题。
为什么要将恢复系数的系数加1.0?
来自:http://en.wikipedia.org/wiki/Coefficient_of_restitution COR通常是[0,1]范围内的数字。从定性上讲,1表示完全弹性碰撞,而0表示完全非弹性碰撞。理论上可能存在大于1的COR,表示产生动能的碰撞,例如将地雷一起投掷并爆炸。
另一个问题是:
/ (im1 + im2)

你正在通过质量倒数之和来除以接触向量上的冲量 - 你可能应该除以质量本身的总和。这会放大你的冲量("她说的就是这个")。

问题与1.0f相同。 - Andrew Hundt
1.0和1.0f之间有什么区别呢? - Andrew Hundt
3
为什么你的有效恢复系数是1.75?也就是说,在碰撞时你向系统中添加了能量,这显然会转化为球体的动能。 - Cade Roux
1.0f 和 1.0 的区别在于,你将 1.0f 指定为浮点类型的 1.0(而不是编译器默认的类型,可能是 float 或 double)。我认为这对问题没有实质影响。 - Cade Roux
根据大多数风格指南,你应该使用 const float 而不是 #define。 - Cade Roux
我取消了对COR的加1.0操作,但是加速度仍然存在。将1.0和1.75之间的差异不会使速度从每次刷新的1.73像素增加到110像素/刷新,正如上面所示。这种效果是由其他方面引起的。 - Andrew Hundt

3

我是你引用的原始球弹跳代码的作者。如果你下载并尝试运行该代码,你会发现它可以正常工作。

以下代码是正确的(与你最初编写的方式相同):

// collision impulse
float i = (-(1.0f + RESTITUTION_CONSTANT) * vn) / (im1 + im2);
CGPoint impulse = ccpMult(mtd, i);

这是非常常见的物理代码,你可以在以下示例中几乎完全看到它的实现方式: 这是正确的,它并没有像其他人所建议的那样创建超过1.0的CoR。这是根据质量和恢复系数计算相对冲量向量。
忽略摩擦力,一个简单的1d示例如下:
J = -Vr(1+e) / {1/m1 + 1/m2}  

其中,e是你的CoR,Vr是你的归一化速度,J是冲量速度的标量值。

如果你计划做更高级的事情,我建议你使用已经存在的许多物理库之一。当我使用上面的代码时,对于几个球来说还好,但当我将其提升到几百个时,它开始卡顿。我使用了Box2D物理引擎,它的求解器可以处理更多的球,并且更加精确。

无论如何,我查看了你的代码,乍一看看起来很好(这是一个相当忠实的翻译)。可能是传递了错误值或向量数学问题的小而微妙的错误。

我不知道任何关于iPhone开发的事情,但我建议在该方法的顶部设置断点,并监视每个步骤的结果值,并找到增长巨大的地方。确保正确计算MTD、碰撞速度等等,直到你看到增加量的位置。

报告该方法中每个步骤的值,我们将看看我们有什么。


0

在这一行中:

CGPoint impulse = ccpMult(mtd, i);

mtd 需要被规范化。错误发生的原因是在原始代码中,mtd 在之前的一行已经被规范化了,但在您的代码中没有。您可以通过执行以下操作来修复它:

CGPoint impulse = ccpMult(ccpNormalize(mtd), i);

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