views:

88

answers:

1

I'm writing an XNA game in C# using the XNA port of Box2d - Box2dx.

Entities like trees or zombies are represented as GameObjects. GameObjectManager adds and removes them from the game world:

    /// <summary>
    /// Does the work of removing the GameObject.
    /// </summary>
    /// <param name="controller">The GameObject to be removed.</param>
    private void removeGameObjectFromWorld(GameObjectController controller)
    {
        controllers.Remove(controller);
        worldState.Models.Remove(controller.Model);
        controller.Model.Body.SetActive(false);
    }

    public void addGameObjectToWorld(GameObjectController controller)
    {
        controllers.Add(controller);
        worldState.Models.Add(controller.Model);
        controller.Model.Body.SetActive(true);
    }

controllers is a collection of GameObjectController instances.

worldState.Models is a collection of GameObjectModel instances.

When I remove GameObjects from Box2d this way, this method gets called:

       void IContactListener.EndContact(Contact contact)
        {
            GameObjectController collider1 = worldQueryUtils.gameObjectOfBody(contact.GetFixtureA().GetBody());
            GameObjectController collider2 = worldQueryUtils.gameObjectOfBody(contact.GetFixtureB().GetBody());
            collisionRecorder.removeCollision(collider1, collider2);
}

worldQueryUtils:

    // this could be cached if we know bodies never change
    public GameObjectController gameObjectOfBody(Body body)
    {
        return worldQueryEngine.GameObjectsForPredicate(x => x.Model.Body == body).Single();
    }

This method throws an error:

System.InvalidOperationException was unhandled
  Message="Sequence contains no elements"
  Source="System.Core"
  StackTrace:
       at System.Linq.Enumerable.Single[TSource](IEnumerable`1 source)
       at etc

Why is this happening? What can I do to avoid it? This method has been called many times before the body.SetActive() was called. I feel that this may be messing it up.

A: 

A few things. The error is actually coming from the Single method because it assumes there will be at least one item in the sequence. If you want more tolerant behavior use SingleOrDefault which will return the default value of that type (if it's a class, null).

Second, the "Body" object ... it may have the equals method overridden, in which case you may get odd results when doing "==". If you are literally looking for the same instance (and it's a class) you can use the object.ReferenceEquals method.

Third, you should rethink your design. Any time you have to loop through a collection to look for a given item (which is all the .Where method does) you have an opportunity to use a better algorithm

Joel Martinez