Collision Exception

May 25, 2011 at 12:39 PM

I'm getting this exception coming up occasionally, is this something i'm not cleaning up correctly?

Can i wrap this in in a try catch in the collision event?

 

Exception caught. Message: KeyNotFoundException 

Trace:    at System.ThrowHelper.ThrowKeyNotFoundException()
   at System.Collections.Generic.Dictionary`2.get_Item(String key)
   at Spritehand.FarseerHelper.PhysicsControllerMain.polygon_Collision(PhysicsSprite source, String spriteCollided)
   at Spritehand.FarseerHelper.PhysicsSprite.HandleCollision(Fixture g1, Fixture g2, Contact manifold)
   at FarseerPhysics.Dynamics.Contacts.Contact.Update(ContactManager contactManager)
   at FarseerPhysics.Dynamics.ContactManager.Collide()
   at FarseerPhysics.Dynamics.World.Step(Single dt)
   at Spritehand.FarseerHelper.PhysicsControllerMain.CompositionTarget_Rendering(Object sender, EventArgs e)
   at System.Windows.Media.CompositionTarget.OnRendering(Object sender, RenderingEventArgs e)
   at MS.Internal.JoltHelper.RaiseEvent(IntPtr target, UInt32 eventId, IntPtr coreEventArgs, UInt32 eventArgsTypeIndex)

 

 

In terms of the stack trace, what are the implications of just skipping this event handler if there aren't any keys in PhysicsObjects.Keys?

 

        void polygon_Collision(PhysicsSprite source, string spriteCollided)        {

            // for now we just STORE the collision because we            

// cannot destroy or inactivate things during a FP3 Step operation!           

if (Collision != null && this.PhysicsObjects.Keys.Contains(spriteCollided))            {
                PhysicsSprite sprite2 = this.PhysicsObjects[spriteCollided];               

CollisionStore.AddCollision(source, sprite2);

                if (PhysicsObjects.Keys.Contains(source.Name) == false)                   

throw new Exception("sprite " + source.Name + " is not in the list of sprites");               

if (PhysicsObjects.Keys.Contains(sprite2.Name) == false)                   

throw new Exception("sprite " + sprite2.Name + " is not in the list of sprites");
            }
        }

 

 

Coordinator
May 25, 2011 at 12:54 PM

It is likely dying on this line : PhysicsSprite sprite2 = this.PhysicsObjects[spriteCollided];               

Because it can't find the sprite in the dictionary any more.

Are you possibly doing your own cleanup/removal of sprites from the PhysicsObjects collection? Are you using a separate thread in your application?

May 25, 2011 at 1:30 PM

Hi Andy,

I'm not using anything special in terms of threading, but i do have a cleanup when either resetting or moving the the next level. I would have thought pausing should stop any collisions that may be pending.

What should i be doing in terms of clearing my physicsContoller object between levels?

 

        private void ClearLevel()
        {
            _physicsController.PauseSimulation = true;

            var spriteCount = _physicsController.PhysicsObjects.Count;


            for (int i = 0; i < spriteCount; i++)
            {
                var sprite = _physicsController.PhysicsObjects.Values.ElementAt(0);
                _cnvGame.Children.Remove(sprite);
                _physicsController.DeletePhysicsObject(sprite.Name);
            }

            _physicsController.PauseSimulation = false;
        }

Coordinator
May 25, 2011 at 1:45 PM

Yeah that looks ok... Below is an example of what I do just so you can compare. Where does ClearLevel get called from? Could it be in your Collision event maybe, so there are more collision events being fired just after it?

           // cleanup the obstacles

           for (int i = _obstaclesInLevel.Count() - 1; i >= 0; i--)

           {

               ObstacleBase obstacle = _obstaclesInLevel[i];

               cnvGame.Children.Remove(obstacle);

               if (obstacle.Sprite != null)

               {

                   _physicsController.DeletePhysicsObject(obstacle.Sprite.Name);

               }

               _obstaclesInLevel.Remove(obstacle);

           }

 

 

May 25, 2011 at 2:02 PM

I think you might be onto something, the ClearLevel is called after hitting a target or a specific collision. So in the method below event handler below it's probably getting to the CollisionStore.AddCollision portion then removing all the physics objects in my ClearLevel method then failing on the last section?? Would commenting out the dictionary checks below have any further implications? Seems like it might solve this particular issue for me.

 

void polygon_Collision(PhysicsSprite source, string spriteCollided)
        {
            // for now we just STORE the collision because we 
            // cannot destroy or inactivate things during a FP3 Step operation!
            if (Collision != null && this.PhysicsObjects.Keys.Contains(spriteCollided))
            {

                PhysicsSprite sprite2 = this.PhysicsObjects[spriteCollided];
                CollisionStore.AddCollision(source, sprite2);


                if (PhysicsObjects.Keys.Contains(source.Name) == false)
                    throw new Exception("sprite " + source.Name + " is not in the list of sprites");
                if (PhysicsObjects.Keys.Contains(sprite2.Name) == false)
                    throw new Exception("sprite " + sprite2.Name + " is not in the list of sprites");

            }

        }

Coordinator
May 25, 2011 at 2:22 PM

All that polygon_Collisione event is doing is collecting all of the collisions during a Step operation in the engine so they can be processed at the end of the Step.

So you should be safe doing what you need in there. Maybe add in a bool flag that shuts off collsion detection for a time.

I guess I haven't hit this situation yet only because my levels don't end right after the collision - the user does a "Next Level" interaction... So this is probably something I will need to add eventually.

May 27, 2011 at 11:53 AM

Hi Again Andy,

I've made a couple of changes to PhysicsControllerMain to do with the collision event and another exception i'm getting intermittently. I'm getting some weird behavior when trying to apply the changes.  All i need to do is build and update the references right? I don't need to do anything in terms of updating blend? It should pick up the behaviors automagically from the project?

When i do this, I have some ellipses don't seem to rotate any more, they seem like the they can't find the boundary object or something. This is the change i made below, any thoughts what i'm doing wrong here?

void polygon_Collision(PhysicsSprite source, string spriteCollided)
        {
            // for now we just STORE the collision because we 
            // cannot destroy or inactivate things during a FP3 Step operation!
            if (Collision != null && this.PhysicsObjects.Keys.Contains(spriteCollided))
            {

                PhysicsSprite sprite2 = this.PhysicsObjects[spriteCollided];
                if (PhysicsObjects.Keys.Contains(source.Name) && PhysicsObjects.Keys.Contains(sprite2.Name))
                	CollisionStore.AddCollision(source, sprite2);

            }

        }

 

Coordinator
May 27, 2011 at 12:09 PM

Note that, when you run the installer for the Physics Helper, it copies the assemblies to C:\Program Files\Physics Helper\  and adds some entries to the Registry so that Blend can find these behaviors at start-up.

So you would want to look at your project references and make sure they are pointing to the modified versions of your assemblies.

It doesn't seem like your changes could affect any boundary detection - they should only affect collision events. Maybe try turning DebugMode="True" on they PhysicsControllerBehavior and see what the boundaries look like.

May 27, 2011 at 12:50 PM
Edited May 27, 2011 at 1:13 PM

Double checked my assemblies they seem OK. There is a definitively a difference between the two. In the original i have an image as the background brush for an ellipse. When physics are applied to it, it reacts as normal bounces rotates etc. But after making the change above the boundary is still correct (after running it in debug) but the image will not rotate. It always stays the same way up, kinda like it's just sliding. Rotating seems like it's disabled??

Screen shot top is the 4.3.0 installer version, bottom is my edited version which is the latest changeset as well:

http://ocau.com/pix/wp2of   

May 27, 2011 at 1:19 PM

HEAD SLAP: The Moment of Inertia was a really high number, not sure why it didn't show up in the first one but problem solved. Sorry for mucking you about. :)