我在Objective-C中实现了问题“Ball to Ball Collision - Detection and Handling”中的代码。然而,每当球以一定角度碰撞时,它们的速度会急剧增加。所有向量数学都是使用cocos2d-iphone完成的,标题为CGPointExtension.h。造成这种不希望的加速的原因是什么?
以下是速度提升的一个例子:
输入:
质量== 12.56637
velocity.x == 1.73199439
velocity.y == -10.5695238
ball.mass == 12.56637
ball.velocity.x == 6.04341078
ball.velocity.y == 14.2686739
输出:
质量== 12.56637
velocity.x == 110.004326
velocity.y == -10.5695238
ball.mass == 12.56637
ball.velocity.x == -102.22892
ball.velocity.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));
}
答案 0 :(得分:5)
通过原始海报审查了原始代码和注释后,代码看起来是一样的,所以如果原件是正确的实现,我会怀疑一个坏的矢量库或某种未初始化的变量。
为什么要在恢复系数中加1.0?
来自:http://en.wikipedia.org/wiki/Coefficient_of_restitution
COR通常是[0,1]范围内的数字。定性地,1表示完全弹性碰撞,而0表示完全非弹性碰撞。大于1的COR在理论上是可能的,表示产生动能的碰撞,例如地雷被抛在一起并爆炸。
另一个问题是:
/ (im1 + im2)
你要用质量的倒数之和除以得到接触矢量的冲动 - 你可能应该除以质量本身的总和。这可以放大你的冲动(“这就是她所说的”)。
答案 1 :(得分:3)
我是那个写过您引用的原始球反弹代码的人。如果您download并尝试该代码,您可以看到它正常工作。
以下代码是正确的(您最初的方式):
// 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,冲击速度等,直到您看到引入大幅增加的位置。
使用该方法中每个步骤的值报告,我们将看到我们拥有的内容。
答案 2 :(得分:0)
在这一行:
CGPoint impulse = ccpMult(mtd, i);
mtd需要规范化。发生错误是因为在原始代码中,mtd在前一行中进行了规范化,但未在代码中进行规范化。您可以通过执行以下操作来解决此问题:
CGPoint impulse = ccpMult(ccpNormalize(mtd), i);