Box2dx: использование World.QueryAABB? - PullRequest
2 голосов
/ 26 марта 2010

Я использую Box2dx с C # / XNA.Я пытаюсь написать функцию, которая определяет, может ли тело существовать в данной точке, не сталкиваясь ни с чем:Как 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;
    }

1 Ответ

4 голосов
/ 02 апреля 2010

World.QueryAABB объявлен так:

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

Как второй параметр, вы, естественно, пропускаете ограничивающий прямоугольник, выровненный по оси.

В качестве первого параметра необходимо передать делегат типа Func<Fixture, bool>. Если вы не знакомы с делегатами, вы можете пока замаскировать их: считайте, что это подсказка, которую вам нужно передать: а) существующую функцию в вашем коде или б) новую функцию, которую можно объявить на лету, если тебе нравится.

Когда вы вызываете 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);

К счастью, этот и связанный с ним синтаксис больше не нужны.)

Другой способ сделать это с помощью лямбда-функции, которая математика говорит для безымянной функции, которую вы определяете на лету.

Эквивалент лямбда-функции для вышеуказанной функции 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 все время, потому что вы перебирали все игровые объекты, включая тот, который вы тестировали; следовательно, он "столкнулся бы" с самим собой.

...