我目前正在使用以下方法来计算两个相互反弹的球体。这是在使用 3D 对象的 2D 乒乓球游戏中使用的(试图将我的头包裹在 3D 周围)。大多数事情都正常工作,但有时(通常当 X 或 Y 速度向同一方向移动时,只是一个比另一个快)物理会做一些奇怪的事情。
返回的浮动只是我用来改变球碰撞时播放的声音的质量差异。任何人都可以在我的计算中看到任何错误:
internal float ResolveCollision(Ball otherBall)
{
if (otherBall == this) { return 0f; }
if (this.GetBoundingSphere().Intersects(otherBall.GetBoundingSphere()))
{
// Attempt to step the balls back so they are just barely touching
Vector3 dd = Position - otherBall.Position;
dd.Normalize();
Position += dd / 2;
otherBall.Position -= dd / 2;
///http://williamecraver.wix.com/elastic-equations
Vector3 V1 = Velocity;
Vector3 P1 = Position;
float M1 = Mass;
float A1 = getMovementAngle(V1.X, V1.Y);
Vector3 V2 = otherBall.Velocity;
Vector3 P2 = otherBall.Position;
float M2 = otherBall.Mass;
float A2 = getMovementAngle(V2.X, V2.Y);
float CA = getContactAngle(P1, P2);
// Recalculate x and y components based of a rotated axis, having the x axis parallel to the contact angle.
Vector3 V1XR = V1 * (float)Math.Cos(A1 - CA);
Vector3 V1YR = V1 * (float)Math.Sin(A1 - CA);
Vector3 V2XR = V2 * (float)Math.Cos(A2 - CA);
Vector3 V2YR = V2 * (float)Math.Sin(A2 - CA);
//Now solve the x components of the velocity as if they were in one dimension using the equation;
Vector3 V1f = (V1 * (M1 - M2) + 2 * M2 * V2) / (M1 + M2);
Vector3 V2f = (V2 * (M2 - M1) + 2 * M1 * V1) / (M1 + M2);
Vector3 V1fXR = (V1 * (float)Math.Cos(A1 - CA) * (M1 - M2) + 2 * M2 * V2 * (float)Math.Cos(A2 - CA)) / (M1 + M2);
Vector3 V2fXR = (V2 * (float)Math.Cos(A2 - CA) * (M2 - M1) + 2 * M1 * V1 * (float)Math.Cos(A1 - CA)) / (M1 + M2);
//Now find the x and y values for the un-rotated axis by equating for the values when the axis are rotated back.
Vector3 V1fX = V1fXR * (float)Math.Cos(CA) + V1YR * (float)Math.Cos(CA + MathHelper.PiOver2);
Vector3 V1fY = V1fXR * (float)Math.Sin(CA) + V1YR * (float)Math.Sin(CA + MathHelper.PiOver2);
Vector3 V2fX = V2fXR * (float)Math.Cos(CA) + V2YR * (float)Math.Cos(CA + MathHelper.PiOver2);
Vector3 V2fY = V2fXR * (float)Math.Sin(CA) + V2YR * (float)Math.Sin(CA + MathHelper.PiOver2);
// Add it all up
Vector3 nV1 = V1fX + V1fY;
Vector3 nV2 = V2fX + V2fY;
///////////////////////////////////////////
// Correct Velocity & Move apart
//////////////////////////////////////////
Velocity = v3check(nV1, MAXSPEED, -MAXSPEED);
otherBall.Velocity = v3check(nV2, MAXSPEED, -MAXSPEED);
// Step the balls forward (by there Velocity) just a bit so they are no longer touching
Position += Velocity * _lastDT * .25f;
otherBall.Position += otherBall.Velocity * otherBall._lastDT * .25f;
return BMDMath.toFloat(Mass - otherBall.Mass);
}
return 0f;
}
我有以下辅助方法来转换一些角度(这可能是问题所在:
private static float getMovementAngle(double vx, double vy)
{
return MathHelper.ToDegrees((float)Math.Atan2(vy, vx));
}
private static float getContactAngle(Vector3 o1, Vector3 o2)
{
Vector3 d = o1 - o2;
return MathHelper.ToDegrees((float)Math.Atan2(d.Y, d.X));
}