2

Box2dxとC#/XNAを使用しています。何かと衝突することなく、特定のポイントにボディが存在できるかどうかを判断する関数を作成しようとしています。

    /// <summary>
    /// Can gameObject exist with start Point without colliding with anything?
    /// </summary>
    internal bool IsAvailableArea(GameObjectModel model, Vector2 point)
    {
        Vector2 originalPosition = model.Body.Position;
        model.Body.Position = point; // less risky would be to use a deep clone

        AABB collisionBox;
        model.Body.GetFixtureList().GetAABB(out collisionBox);

        // how is this supposed to work?
        physicsWorld.QueryAABB(x => true, ref collisionBox);

        model.Body.Position = originalPosition;
        return true;
    }

これを行うためのより良い方法はありますか?どのように機能World.QueryAABBすることになっていますか?

これは以前の試みです。壊れています; 常にfalseを返します。

    /// <summary>
    /// Can gameObject exist with start Point without colliding with anything?
    /// </summary>
    internal bool IsAvailableArea(GameObjectModel model, Vector2 point)
    {
        Vector2 originalPosition = model.Body.Position;
        model.Body.Position = point; // less risky would be to use a deep clone

        AABB collisionBox;
        model.Body.GetFixtureList().GetAABB(out collisionBox);

        ICollection<GameObjectController> gameObjects = worldQueryEngine.GameObjectsForPredicate(x => ! x.Model.Passable);

        foreach (GameObjectController controller in gameObjects)
        {
            AABB potentialCollidingBox;
            controller.Model.Body.GetFixtureList().GetAABB(out potentialCollidingBox);

            if (AABB.TestOverlap(ref collisionBox, ref potentialCollidingBox))
            {
                model.Body.Position = originalPosition;
                return false; // there is something that will collide at this point
            }
        }
        model.Body.Position = originalPosition;
        return true;
    }
4

1 に答える 1

4

World.QueryAABB は次のように宣言されます。

public void QueryAABB(Func<Fixture, bool> callback, ref AABB aabb)

2 番目のパラメーターとして、当然、関心のある軸に沿ったバウンディング ボックスを渡します。

最初のパラメーターとして、タイプのデリゲートを渡す必要がありますFunc<Fixture, bool>。デリゲートに慣れていない場合は、今のところざっと説明しておいてください。これは、a) コード内の既存の関数、または b) 次の場合にオンザフライで宣言できる新しい関数のいずれかを渡す必要があるという手がかりと考えてください。あなたが好きです。

QueryAABB を呼び出すと、指定したバウンディング ボックスに重なるオブジェクトが見つかるたびにコールバックされます。バウンディング ボックスに重なっている 3 つのオブジェクトが見つかった場合は、オブジェクトごとに 1 回ずつ、関数を 3 回呼び出します。戻ってくるたびにtrue、「ありがとう、検索を続けてください」falseと言うか、「いいですね、もう検索しないでください」と言うことができます。

したがって、使用例の 1 つは次のようになります。

private bool m_foundCount = 0;

internal bool IsAvailableArea(GameObjectModel model, Vector2 point)
{
    ...
    m_foundCount = 0;
    physicsWorld.QueryAABB( OnFoundSomething, ref collisionBox);
    Debug.WriteLine(string.Format("Found {0} fixtures in total", m_foundCount));
    ..
}

internal bool OnFoundSomething(Fixture found)
{
    Debug.WriteLine(string.Format("Found fixture {0}", found));
    ++m_foundCount;
    return true; // true to carry on searching, false when done
}

(余談ですが、これは以前はさらに長く使用されていました。以前のバージョンの C# では、次のように OnFoundSomething をデリゲートで明示的にラップする必要がありました。

physicsWorld.QueryAABB( new Func<Fixture, bool>(OnFoundSomething), ref collisionBox);

ありがたいことに、これと関連する構文は、一般的に必要なくなりました。)

それを行うもう1つの方法は、ラムダ関数を使用することです。これは、数学者がその場で定義する名前のない関数を代弁します。

上記の OnFoundSomething 関数に相当するラムダ関数は次のとおりです。

found =>
{
    Debug.WriteLine(string.Format("Found fixture {0}", found)); 
    ++m_foundCount; 
    return true;
}

したがって、唯一の違いは、関数には名前がなく、その戻り値と引数の型は、それを使用するコンテキストから計算されることです。次のように:

internal bool IsAvailableArea(GameObjectModel model, Vector2 point)
{
    ...
    m_foundCount = 0;
    physicsWorld.QueryAABB( found =>
    {
        Debug.WriteLine(string.Format("Found fixture {0}", found)); 
        ++m_foundCount; 
        return true;
    }, ref collisionBox );
    Debug.WriteLine(string.Format("Found {0} fixtures in total", m_foundCount));
    ..
}

以前の試みに関しては、確かではありませんが、テストしていたものを含むすべてのゲームオブジェクトを反復していたため、常に false を返していたのではないかと思います。したがって、それはそれ自体と「衝突」していたでしょう。

于 2010-04-01T21:50:44.707 に答える