2010-03-26 5 views
2

J'utilise Box2dx avec C#/XNA. Je suis en train d'écrire une fonction qui détermine si un corps pouvait exister dans un point donné sans entrer en collision avec quoi que ce soit:Box2dx: Utilisation de 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); 

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

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

Y at-il une meilleure façon de s'y prendre pour le faire? Comment fonctionne le World.QueryAABB?

Voici une tentative antérieure. Elle est cassée; il retourne toujours faux.

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

Répondre

4

World.QueryAABB est déclarée comme ceci:

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

En tant que second paramètre vous passez la zone de délimitation aligné de l'axe qui vous intéresse, naturellement.

Comme premier paramètre, vous devez passer dans un délégué de type Func<Fixture, bool>. Si vous n'êtes pas familier avec les délégués, vous pouvez les ignorer pour le moment: considérez ceci comme un indice que vous devez passer soit a) une fonction existante dans votre code ou b) une nouvelle fonction que vous pouvez déclarer à la volée si vous aimez. Lorsque vous appelez QueryAABB, il vous rappelle à chaque fois qu'il trouve un objet qui chevauche la boîte de délimitation que vous fournissez. S'il trouve trois objets chevauchant votre boîte englobante, il appellera votre fonction trois fois, une fois par objet. Chaque fois que vous pouvez retourner true pour dire "merci, continuez la recherche" ou false pour dire "c'est bon, ne cherchez plus".

donc un exemple d'utilisation serait:

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 
} 

(En aparté, cette habitude d'être encore plus longtemps, les versions antérieures de C# Devez-vous envelopper explicitement un délégué autour OnFoundSomething, à la:

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

Heureusement cela et la syntaxe connexe n'est généralement plus nécessaire.)

L'autre façon de le faire est avec une fonction lambda, qui est mathématicien pour parler fonction sans nom que vous définissez à la volée.

La fonction équivalente lambda à la fonction OnFoundSomething ci-dessus est:

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

La seule différence est que la fonction ne porte pas de nom, et le type de sa valeur de retour et les arguments sont élaborés à partir le contexte dans lequel vous l'utilisez. Comme dans:

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

En ce qui concerne votre première tentative, je ne suis pas certain, mais je pense qu'il peut avoir été soit faux tout le temps parce que vous itérer tous les objets du jeu, y compris celui que vous testiez; par conséquent, il aurait été "en collision" avec lui-même.