带有Farseer Physics的C#XNA中的OnCollision事件处理程序问题

时间:2010-07-22 10:50:42

标签: c# xna farseer

此刻我的游戏中的这个工作正常(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; 
} 

我在很久以前刚刚玩的时候把它放进去了。这在某些情况下会引起一些问题。例如,如果一个灵长类固定在地板上而另一个灵长类动物从一个体面的高度落到它上面,几乎总是如此,掉落的盒子会爆炸并且休息盒会存活下来。此外,如果两个盒子并排落下并互相给予最小的触摸,那么两个盒子都会吹到半空中。嗯,不是那么完美。有谁知道如何改进我的碰撞处理程序?提前致谢。

3 个答案:

答案 0 :(得分:8)

好的,我的other answer是可行的。但是我更仔细地研究了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;
        }
    }
}

Apparently歧管中的脉冲数据只能在PostSolve中正确设置,而不能在OnCollision中正确设置。

答案 1 :(得分:6)

(虽然这是目前接受的答案 - 我会指示任何人到我的other answer寻求潜在的优越方法。)

您对冲击力的计算完全错误。你需要在接触点获得相对速度 - 你得到的东西很奇怪......

您的代码看起来像是使用Farseer 3.0(您应该指定,因为它更像是Box2DX的分支而不是Farseer 2.1)。我在Farseer 2.1中做了什么(你有ContactList contacts而不是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;

ManifoldManifoldPoint都有成员:

public Vector2 LocalPoint;

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

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

答案 2 :(得分:2)

我没有使用XNA,但作为一个物理问题,为什么不从B的线速度中减去A的线速度,得到'力'作为结果矢量的平方(总和的平方组件)?对于一个非常简单的物理模型,即使我们忽略质量(或者就此而言,弹性或能量与能量之间的区别),这应该与根据“E =(mv ^ 2)/ 2”所涉及的动能相协调。动量)。如果物体以相同的速度在相同的大致方向上移动,则得到一个小值;如果一个人正在高速接近(或者,当然,离开!),你会得到一个很大的价值。