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工作?

这是较早的尝试。它被打破; 它总是返回假。

    /// <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)

作为它的第二个参数,您自然会传递您感兴趣的轴对齐边界框。

作为第一个参数,您需要传入一个类型的委托Func<Fixture, bool>。如果您不熟悉委托,您可以暂时忽略它们:认为这是一个线索,您需要传入 a) 代码中的现有函数或 b) 可以动态声明的新函数,如果你喜欢。

当您调用 QueryAABB 时,它会在每次找到与您提供的边界框重叠的对象时回叫您。如果它发现三个对象与您的边界框重叠,它将调用您的函数三次,每个对象一次。每次你可以返回true说“谢谢,继续搜索”或false说“那很好,不要再搜索了”。

因此,一个示例用法是:

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

谢天谢地,这个和相关的语法通常不再需要。)

另一种方法是使用 lambda 函数,这是数学家为您动态定义的无名函数而说话。

与上述 OnFoundSomething 函数等效的 lambda 函数是:

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 回答