6

現時点では、私のゲームでは問題なく動作していますが、私は数学が得意ではありません。2 つのプリミティブが衝突したとき、プリミティブに加えられた力が設定されたしきい値を超えた場合、それらが小さな破片に砕けるようにしたいと考えています。現在の衝突イベント ハンドラーは次のようになります。

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; 
} 

ずっと前に遊んでいたときにそれを入れました。これにより、特定の状況で少し問題が発生します。たとえば、プリミティブが床に静止していて、別のプリミティブが適切な高さからその上に落下した場合、ほとんどの場合、落下したボックスは爆発し、静止しているボックスは生き残ります。また、2 つのボックスが並んで落下し、互いにわずかな接触を与えると、両方のボックスが空中で爆破されます。うーん、それは完璧ではありません。私の衝突ハンドラーを改善する方法を知っている人はいますか? 前もって感謝します。

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の代わりに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 つのオブジェクトを分割する必要があるとマークし、物理演算の更新の実行が終了した後に (衝突ハンドラーではなく) 実際に分割することをお勧めします

于 2010-07-22T11:20:06.233 に答える
2

私は XNA を使用していませんが、物理の問題として、B の線速度から A の線速度を差し引いて、結果のベクトルの 2 乗として「力」を取得してみませんか (成分の 2 乗を合計します)。 ? これは、非常に単純な物理モデルの場合、「E=(mv^2)/2」に従って含まれる運動エネルギーと調和するはずです。勢い)。オブジェクトがほぼ同じ方向に同じ速度で移動している場合、小さな値が得られます。1 つが高速で接近している (または、もちろん、離れている!) 場合は、大きな値が得られます。

于 2010-07-22T11:11:27.287 に答える