2011-01-26 9 views
3

box2d as3 b2ContactListenerクラスに問題があります。私は、b2ContactListenerを拡張し、PostSolveメソッドをオーバーライドするContactListenerというクラスを持っています。 PostSolveには、2つのパラメータ、連絡先を持つ2つのオブジェクトに関する情報を保持する連絡先、および連絡先に関する情報を保持するインパルスがあります。私はインパルスパラメータを使用して2つのオブジェクトがどれほど難しいかを判断し、それに応じてダメージを適用します。私は円形で何かを作る場合 、それはゆっくりと動いてますが、地面上の任意の場所に円をかなり大きなオブジェクトをドロップし、地面と私が持っている静的なボディにロールしてみましょう。ここではBox2d As3コンタクトリスナーの問題

が問題ですコンタクトを取ることは、繰り返すようなインパルスになります。ローリング円形オブジェクトは、そうしてはならないときに壊れます。

静的な物体を振って数百メートル離れた物体に大きなダメージを与えているように、しかしサークルにしか影響しません。

状況に誰かが気をつけてもらえますか?これは既知の問題ですか?回避策?

私はBox2DAs3バージョン2.1aを使用しています。

更新:身体がこのような奇妙な状態になったら、それに触れるサークルには大きなインパルスがたくさんあります。非円形のものが体に接触すると、もはや問題はありません。また、この問題は静的オブジェクトだけでなく、動的および運動学的な問題でもあります。

更新:私はさらに問題を絞り込んだ。コンタクトリスナーは、大きなオブジェクトの平坦なエッジが地面に当たったときに、大きな衝撃を与えて、大きな衝撃を与えます。目を覚まして地面に触れるオブジェクトだけではなく、何回でもPostSolveメソッド呼び出しが得られます。私は地面に円が転がっている間に地面に11ピクセル×11ピクセルのサイズのボックスを落とそうとしました。バグは起こりませんでした。しかし、ボックスが12×12の場合、バグは発生します。また、サイズが12のボックスを0.1度から0.1度回転させると、バグは発生しません。それを再現するのに十分な接触面積が必要です。また、ボックスの密度は何も影響しません。また、ボックスが幅が10で高さが100の長方形で、バグが再現される場合もあります。それはオブジェクトの大きさがバグを引き起こしているのとほぼ同じです。コンタクトサイズの領域ではないかもしれません。

更新:ここに私が作成したBox2Dフォーラムの投稿へのリンクがあります。ソースにはswfの例があります。

Link

+0

私はbox2dについては何も知りませんが、実際には一定の円だけでなく回転するものにも影響します。 – Beta

+0

睡眠円、睡眠中および覚醒中のポリゴンはすべて影響を受けません。 – Jordan

+0

魅力的!これはbox2dのバグのように思えますし、クリーンな回避策はないと思います。 – Beta

答えて

0

WOW。だから私はついにその問題が何かを知りました。

私は、ContactListenerで何か面白いことをすることで回避策があるかどうかを試してみるうちに、PostSolveメソッドがどこから呼び出されているか調べてみることにしました。これはb2Islandという名前のクラスから来ており、それはそのクラスのReport関数から来ています。一見、問題を簡単に見つけました。彼女は、関数である:それはb2Islandクラスのすべてのインスタンスで同じになります(1、より多くがある場合)、またそれがどの時点でリセットを取得していないので、

private static var s_impulse:b2ContactImpulse = new b2ContactImpulse(); 
public function Report(constraints:Vector.<b2ContactConstraint>) : void 
{ 
    if (m_listener == null) 
    { 
     return; 
    } 

    for (var i:int = 0; i < m_contactCount; ++i) 
    { 
     var c:b2Contact = m_contacts[i]; 
     var cc:b2ContactConstraint = constraints[ i ]; 

     for (var j:int = 0; j < cc.pointCount; ++j) 
     { 
      s_impulse.normalImpulses[j] = cc.points[j].normalImpulse; 
      s_impulse.tangentImpulses[j] = cc.points[j].tangentImpulse; 
     } 
     m_listener.PostSolve(c, s_impulse); 
    } 
} 

はそうそう明らかs_impulseのvarが静的です。 s_impulse varへの参照はすべて上で見ることができるので、他に何も起こりません。しかしここにポイントがあります。サークルにはポリゴンとの接触が1つしかありません。つまり、レポートされたときに1つの連絡先に対してインパルスを設定します。もう一方の接点は、リセットされていなければ、最後に報告される物体の最後のインパルスを持つ。

基本的には、サークルに見られるインパルスは、実際に報告されたものからのインパルスの上に残ります。これを修正するには:

private static var s_impulse:b2ContactImpulse = new b2ContactImpulse(); 
public function Report(constraints:Vector.<b2ContactConstraint>) : void 
{ 
    if (m_listener == null) 
    { 
     return; 
    } 

    for (var i:int = 0; i < m_contactCount; ++i) 
    { 
     s_impulse = new b2ContactImpulse(); 

     var c:b2Contact = m_contacts[i]; 
     var cc:b2ContactConstraint = constraints[ i ]; 

     for (var j:int = 0; j < cc.pointCount; ++j) 
     { 
      s_impulse.normalImpulses[j] = cc.points[j].normalImpulse; 
      s_impulse.tangentImpulses[j] = cc.points[j].tangentImpulse; 
     } 
     m_listener.PostSolve(c, s_impulse); 
    } 
} 

これは簡単です。