6

我目前在我的游戏中可以正常工作(ish),但我的数学并不出色。当两个原始动物碰撞时,如果施加在原始动物身上的力超过设定的阈值,我希望它们粉碎成小块。我目前的碰撞事件处理程序看起来像这样。

public bool Collision(Fixture fixtureA, Fixture fixtureB, Manifold manifold) 
{ 
   Vector2 position = manifold.LocalNormal; 
   float angle = (float)Math.Atan2(position.Y, position.X); 
   Vector2 force = Vector2.Zero; 
   if (angle < 0) 
     force = new Vector2((float)(Math.Cos(angle) * fixtureA.Body.LinearVelocity.X), (float)Math.Sin(MathHelper.TwoPi + angle) * fixtureA.Body.LinearVelocity.Y); 
   else 
     force = new Vector2((float)(Math.Cos(angle) * fixtureA.Body.LinearVelocity.X), (float)Math.Sin(MathHelper.TwoPi - angle) * fixtureA.Body.LinearVelocity.Y); 
   double XForce = Math.Sqrt(force.X * force.X); 
   double YForce = Math.Sqrt(force.Y * force.Y); 
   double totalForce = XForce + YForce; 
   if ((Breakable) && (totalForce > BreakForce)) 
   { 
      Breakable = false; 
      Active = false; 
      BreakUp(fixtureA, fixtureB); 
   } 
   return true; 
} 

很久以前我只是在玩的时候把它放进去。这在某些情况下会导致一些问题。例如,如果一个原始动物静止在地板上,而另一个原始动物从一个合适的高度落到它上面,几乎总是,落下的盒子会爆炸,而静止的盒子会幸存下来。此外,如果两个盒子并排掉落并相互接触,那么两个盒子都会在半空中炸毁。嗯,不是很完美。有谁知道如何改进我的碰撞处理程序?提前致谢。

4

3 回答 3

8

好的,所以我的另一个答案是可行的。但是我更仔细地查看了 Farseer 3.0(当前的 SVN 版本),发现它已经几乎完全实现了您正在尝试做的事情。

寻找“ BreakableBody.cs ”。您也许可以直接使用它 - 但否则您可以复制出您想要的功能。

OnCollision具体来说:您不想将功能附加到您的夹具上,而是将一个附加到PostSolve. 它需要一个ContactConstraint你可以潜入并找到碰撞的冲动。

这是该函数的实现BreakableBody

private void PostSolve(ContactConstraint contactConstraint)
{
    if (!Broken)
    {
        float maxImpulse = 0.0f;
        for (int i = 0; i < contactConstraint.manifold.PointCount; ++i)
        {
            maxImpulse = Math.Max(maxImpulse,
                         contactConstraint.manifold.Points[0].NormalImpulse);
            maxImpulse = Math.Max(maxImpulse,
                         contactConstraint.manifold.Points[1].NormalImpulse);
        }

        if (maxImpulse > Strength)
        {
            // Flag the body for breaking.
            _break = true;
        }
    }
}

显然,流形中的脉冲数据仅在 中正确设置PostSolve,而不是在 中OnCollision

于 2010-07-22T14:20:45.057 回答
6

(虽然这是目前公认的答案 - 我会引导任何人使用我的其他答案以获得可能更好的方法。)

你对冲击力的计算是完全错误的。你需要得到接触点的相对速度——你得到了一些很奇怪的东西......

您的代码看起来像是在使用 Farseer 3.0(您应该指定,因为它比 Farseer 2.1 更像是 Box2DX 的一个分支)。我在 Farseer 2.1(你有ContactList contacts而不是 a Manifold)中为获得冲击速度所做的是:

foreach(Contact contact in contacts)
{
    Vector2 position = contact.Position;
    Vector2 v0;
    me.Body.GetVelocityAtWorldPoint(ref position, out v0);
    Vector2 v1 = new Vector2();
    if(!hit.Body.IsStatic)
        hit.Body.GetVelocityAtWorldPoint(ref position, out v1);
    v0 -= v1;

    float hitVelocity = v0.Length();
    // To then get the force, you need the mass of the two objects
}

简单看一下 Farseer 3.0 的源码,似乎Manifold有一个成员:

public FixedArray2<ManifoldPoint> Points;

并且Manifold都有ManifoldPoint成员:

public Vector2 LocalPoint;

修改我的 Farseer 2.1 代码以使用它们应该相当简单。

另外:我建议简单地将这两个对象标记为需要破坏,然后在物理更新完成运行(而不是在碰撞处理程序中)实际破坏它们。

于 2010-07-22T11:20:06.233 回答
2

我没有使用 XNA,但作为一个物理问题,为什么不直接从 B 的线速度中减去 A 的线速度,并将“力”作为结果向量的平方(将分量的平方和) ? 对于一个非常简单的物理模型,即使我们忽略质量(或者,就此而言,弹性或能量与势头)。如果物体以相同的速度在相同的大致方向上移动,你会得到一个小值;如果一个人正在高速接近(或者,当然,离开!),你会得到一个很大的价值。

于 2010-07-22T11:11:27.287 回答