Box2dx:World.QueryAABB 的用法?

发布于 2024-08-26 08:06:00 字数 1934 浏览 11 评论 0原文

我将 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;
    }

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

三生一梦 2024-09-02 08:06:00

World.QueryAABB 的声明如下:

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

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

作为第一个参数,您需要传入 Func 类型的委托。如果您不熟悉委托,您现在可以忽略它们:将此视为您需要传入 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 周围,la:

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,因为您正在迭代所有游戏对象,包括您正在测试的对象;因此它会与自身“碰撞”。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文