views:

217

answers:

1

I'm using Box2dx with C#/XNA. I'm trying to write a function that determines if a body could exist in a given point without colliding with anything:

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

Is there a better way to go about doing this? How is World.QueryAABB supposed to work?

Here is an earlier attempt. It is broken; it always returns 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;
    }
A: 

World.QueryAABB is declared like this:

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

As its second parameter you pass the axis aligned bounding box you're interested in, naturally.

As the first parameter you need to pass in a delegate of type Func<Fixture, bool>. If you're not familiar with delegates, you can gloss over them for now: consider this a clue that you need to pass in either a) an existing function in your code or b) a new function which you can declare on the fly if you like.

When you call QueryAABB, it will call you back each time it finds an object which overlaps the bounding box you provide. If it finds three objects overlapping your bounding box, it will call your function three times, once per object. Each time you can return true to say "thanks, carry on searching" or false to say "that's good, don't search any more".

So one example usage would be:

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
}

(As an aside, this used to be even longer; earlier versions of C# required you to explicitly wrap a delegate around OnFoundSomething, a la:

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

Thankfully this and related syntax is no longer generally required.)

The other way to do it is with a lambda function, which is mathematician speak for a nameless function you define on the fly.

The equivalent lambda function to the above OnFoundSomething function is:

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

So the only difference is that the function doesn't have a name, and the type of its return value and argument are worked out from the context in which you use it. As in:

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

With regard to your earlier attempt, I'm not certain but I suspect it may have been returning false all the time because you were iterating over all game objects, including the one you were testing; hence it would have been "colliding" with itself.

El Zorko