5

私が取り組んでいる中規模の Flash ゲームで、初めて Box2D を真剣に使用しています。Box2D に関する私の現在の経験は、ワールド、ボディを作成し、それらのボディを機能的な方法でワールドに追加することに限定されています。

Box2D を自分のゲーム環境に統合するのは十分に簡単だと思います。適切に記述されたコードを維持し、衝突の処理を説明するいくつかのチュートリアルを完了しました。私が今直面している問題は、私のゲームには多くの本体があり、それぞれがさまざまな方法で他の本体と相互作用することですb2ContactListener。非常に面倒になることなく、独自のサブクラスを作成するのは難しいと感じています。

私が使用したチュートリアルに基づいて、独自のサブクラスを作成b2ContactListenerし、メソッドのオーバーライドを追加しましたBeginContact()BeginContact()呼び出されたときに受け取る引数は、 のインスタンスを参照します。これにより、2 つのインスタンス (衝突した 2 つのインスタンス) にb2Contactアクセスできます。その後、これらの各 に関連付けられb2Fixtureたインスタンスにアクセスできます。b2Bodyb2Fixture

  • 問題:現在、2 つのものが衝突したもの (つまり、壁とミサイルなのか、プレイヤーと木なのかなど) を見つける回り道があります。GetUserData()これは、例として次のように使用します。

    var f1Player:Boolean = contact.GetFixtureA().GetBody().GetUserData() is Player
    var f2Player:Boolean = contact.GetFixtureB().GetBody().GetUserData() is Player
    var f1Tree:Boolean = contact.GetFixtureA().GetBody().GetUserData() is Tree
    var f2Tree:Boolean = contact.GetFixtureB().GetBody().GetUserData() is Tree
    // ... continutes with all possible combinations.
    
    
    // Example of managing a collision:
    if(f1Player && f2Tree)
    {
        // Player (FixtureA) and Tree (FixtureB)
    }
    
    if(f2Player && f1Tree)
    {
        // Player (FixtureB) and Tree (FixtureA)
    }
    

    ご覧のとおり、これは非常に長くなり、管理不能になります。また、FixtureA または FixtureB、またはその逆の特定の要素に対応するために 2 回実行するアクションの各セットを作成する必要があります (明らかに、文字通り書き直すのではなく、パラメータを入れ替えた関数呼び出しの形式で)。

これは明らかに正しいアプローチではありませんが、衝突検出の管理について詳しく説明しているリソースを見つけることができませんでした。

共有できる Box2D を使用した衝突検出管理の経験がある人はいますか? また、SetUserData( entityThatOwnsTheBody );その方法を使用する正しい方法を使用していますか?

4

3 に答える 3

2

ええ、確かにちょっと面倒です。実際、あなたのやり方はかなり典型的だと思います。

fwiw Box2D 自体は、フィクスチャがオーバーラップしているかどうかをテストするときに、同様の問題に対処する必要があります。b2CollideCircles、b2CollidePolygonAndCircle、b2CollidePolygons などの関数が多数あり、2 つのフィクスチャが互いに近づくと、エンジンはこれらの関数のどれを使用するかを選択します。

関数ポインターを 2 次元配列に配置することでこれを行い、2 つの形状タイプをインデックスとして使用して、この配列内の適切な関数を検索します。詳細については、b2Contact.cpp の最初の 3 つの関数を参照してください。

もちろん、AS3 でこのような関数参照を渡すことができない場合、この回答はあまり役に立たないと思いますが、C/C++/JS ユーザーが来るかもしれないので、とにかく投稿すると思いました。

于 2012-10-03T21:03:26.930 に答える
1

オリジナルよりもずっといいものを思いついた。

まず、自分のBeingクラス(を所有しているb2Body)に自分自身をその本体として設定させますUserData。このクラスにもonContact()メソッドが含まれ、次のようになります。

public class Being
{

    private var _body:b2Body;


    public function Being()
    {
        // Define the body here.
        // ...

        _body.SetUserData(this);
    }


    public function onCollision(being:Being = null):void
    {
        //
    }

}

次に、私自身のb2ContactListener実装では、衝突するもの(または、衝突するものに割り当てられていBeingない場合はnull )を反対側のものに渡すだけです。Beingb2BodyUserDataBeingonCollision()

override public function BeginContact(contact:b2Contact):void
{
    var bodyA:b2Body = contact.GetFixtureA().GetBody();
    var bodyB:b2Body = contact.GetFixtureB().GetBody();

    var beingA:Being = bodyA.GetUserData() as Being || null;
    var beingB:Being = bodyB.GetUserData() as Being || null;

    beingA && beingA.onCollision(beingB);
    beingB && beingB.onCollision(beingA);
}

そして最後に、の各サブクラスで、特定のタイプのBeing他のs間の衝突に適したロジックを簡単に準備できます。Being

class Zombie extends Being
{
    override public function onCollision(being:Being = null):void
    {
        if(being && being is Bullet)
        {
            // Damage this Zombie and remove the bullet.
            // ...
        }
    }
}
于 2012-10-11T09:58:10.937 に答える
1

c++のバージョンを使用しましBox2dたが、アクションスクリプトでも同じアプローチが機能すると思います。ポインターとグラフィカル表現へのポインターObjectを含むクラスを作成します。はを指すように設定されました。クラスには次のメソッドがありました。b2Body *_body_bodyUserDataObject *Object

virtual bool acceptsContacts    ();
virtual void onContactBegin     (const ContactData &data);
virtual void onContactEnded     (const ContactData &data);
virtual void onContactPreSolve  (const ContactData &data);
virtual void onContactPostSolve (const ContactData &data);

サブクラスで衝突が検出されたb2ContactListener場合、衝突したボディにユーザー データがあるかどうかをチェックしました。もしそうなら、それはユーザーデータをキャストしObject*、衝突したオブジェクトのいずれかが連絡先を受け入れた場合、ContactData(衝突に関するすべての必要な情報を含むクラス) を作成listし、後で配信するために内部に配置します。

メソッドがb2World::update返されると、ContactListenerすべての連絡先情報をオブジェクトに渡して処理します。衝突を処理しているときに新しいボディ、ジョイントなどを作成できるようにするために、配信が遅れました (更新の実行中は許可されません)。

また、衝突処理中に衝突したボディの 1 つが削除された場合は、通知する必要がありますContactListener(内部へのポインターを配置するだけです)。これにより、適切な連絡先が無効になり、それらが配信されなくなります。ContactData

于 2012-10-03T08:59:45.190 に答える