Question About Implementing BeginContact, EndContact, PreSolve, PostSolve Events

Topics: User Forum
Jul 28, 2012 at 7:03 PM
Edited Jul 28, 2012 at 7:05 PM

Could someone please advise me if I doing this right. I have Sprite classes for my game objects. Each SpriteXXX has its own OnCollision and OnSeparation event methods.

I'd like to be able to Calculate Impact Impulse when doing collision checks. I have a private World data member that gets passed into the SpriteXXX class on construction.

Is it OK if I did this in my constructor, not sure if this is the right way to get BeginContact, EndContact, PreSolve, PostSolve events.

Just trying to get feedback if this is an OK implementation or there is an easier or more efficient approach so I am not duplicating or adding work to the process.

Code: Inside my SpriteXXX class

//inside constructor of my SpriteXXX class
this.world.ContactManager.BeginContact += new BeginContactDelegate(BeginContact);
this.world.ContactManager.EndContact += new EndContactDelegate(EndContact);
this.world.ContactManager.PreSolve += new PreSolveDelegate(PreSolve);
this.world.ContactManager.PostSolve += new PostSolveDelegate(PostSolve);

//Stubs for my methods for those events...
public bool BeginContact(Contact contact) 
{
    //do something here...
    return true;
}

public void EndContact(Contact contact)
{
    //do something here...
}

public void PreSolve(Contact contact, ref Manifold oldManifold)
{
    //do something here...
}

public void PostSolve(Contact contact, ContactConstraint impulse)
{
    //do something here...
}
Jul 28, 2012 at 7:57 PM

The way this is written each instance of the SpriteXXX class will attach contact event handlers to the world. But they are going to be called for each contact even if the SpriteXXX does not participate in that particular collision. So Sprite1 will get called for the collisions of Sprite2 and Sprite3 and so on.

You should have one set of global handlers. Attach them after world creation for example. They could also be static methods of the base Sprite class. I assume the SpriteXXX is a class to unite graphics and physics, although I'd name it differently. Or they could be virtual methods of the base Sprite to override in children for custom contact handling.

Then you can store a reference to the actual SpriteXXX instance in the UserData of the Body/Fixture when you create it and inside the global handlers pull out which concrete SpriteXXX instance is actually participating in that particular contact and call its handler methoda.

An alternative would be to have a global contact manager that knows how to handle contacts between SpriteXXX-es instances based on some game logic. Advantage is one central location. Disadvantage - a lot of custom behaviors will clutter the code and turn it into an OOP anti-pattern. I usually start like this and refactor later if the needs become more complex.

Jul 28, 2012 at 10:33 PM
Edited Jul 28, 2012 at 10:34 PM

@jerrysb - There is already an instance of 'World' in my project. How can I just piggy back on that event and grab the data I need. I could just create private methods for  

//BeginContact(...), EndContact(...), PreSolve(...) & PostSolve(...)

and in my Event Handler for

OnCollision() {... return true;}

do a check for contact.IsTouching() and assign info from world.ContactBegin, etc to my private methods.

Is that good idea?

If not could you please throw a sample code snippet, how would I go about doing what you said in the second paragraph of your initial reply.

Please advise. 

 

Jul 29, 2012 at 1:57 PM
Edited Jul 29, 2012 at 1:59 PM

Hmm it's not clear what you are trying to achieve. First of all Begin/EndContact and Pre/PostSolve are Box2D specific callbacks. OnCollision/OnSeparation is a Farseer extension. ATM it has issues (see http://farseerphysics.codeplex.com/workitem/31331). Even though the Farseer way is very good for per class collision handling I still prefer the Box2D way. Most certainly you have to be very careful if you mix them since they duplicate functionality i.e. EndContact carries mostly the same info as OnSeparation.

So I'd go like this:. Attach collision handlers to the World for Begin/EndContact. When BeginContact() is called you have a collision. Use FixtureA and FixtureB of the Contact variable, get the UserData which is your class instance that you've set at body creation and pass the info that a contact has ocurred to your class instance for further processing. Note that unlike the Farseer-style OnCollision/OnSeparation in the Contact class the order of the fixtures is random so you have to figure out what does FixtureA represent and same for FixtureB. For example if you have a ball hitting the ground the ball can be FixtureA or it can be FixtureB so figure out who should receive information - ball, ground,  both or none (manipulate the contact right there). That's where you probably need UserData.

Here's a tutorial for Box2D that explain this stuff in more detail:

http://www.iforce2d.net/b2dtut/collision-anatomy

Jul 29, 2012 at 2:15 PM

The link from iforce2d.net is what I was trying to replicate in my project. What it seems like is there are no 'Contact Listeners' in Farseer like it does in Box2D. The reason why I attached the 4 events to the world instance is the best of my knowledge I could think of to mimic that.

Please advise how Farseer handles it, code snippet it possible since I am a visual learner.

I am a newbie to Farseer and its hard to make sense of a lot of code base in Farseer, the comments in code are not always clearly explained or no comments at for method calls or a good set of documentation except asking for help in the forum. I understand the developers have a day job and a life but it just feels like injustice since this is a really good physics engine and I really want to use it. I would volunteer to update te documentation section of this project but I am very new and still learning C# (events & delegates) and Farseer.

Jul 29, 2012 at 3:28 PM

I think I wasn't quite clear in the previous post. I meant that Farseer implements both Box2D style contact handlers in the world object as well as it's own specialization OnCollision/OnSeparation. If you use Begin/EndContact and Pre/PostSolve you get the exact same behaviour as if you were working with Box2D in C++.

The code you posted at the very beginning is good with the caveat that you shouldn't attach events in the constructor of each SpriteXXX instance but rather do it once where you create the World object. When the handlers are called you get passed a Contact variable to let you figure out what's colliding and from the UserData you can pull your SpriteXXX object if necessary and call methods on it with the contact information.

In the code you posted you attach to the world in each instance of SpriteXXX. The way you had written it would mean that if you had 1000 SpriteXXX instances the BeginContact handler for a collision between body1 and body2 would be called on each of those 1000 instances that are subscribed to the event (so a total of 1000 method calls). Those would be superfluous at best because what does body999 care if body1 and body2 are colliding? It's not wrong but inefficient and also you'd still need to figure out in the handler which bodies are actually colliding. This is because it's an event on a "global" object as in there is one World and one ContactManager. That's the Box2D way.

Compare and contrast this to the Farseer way. OnCollision/OnSeparation/BeforeCollision/AfterCollision are events declared on a *per fixture* basis. They get fired only when that particular fixture is colliding and the subscribed fixture is provided as the first parameter. That's what permits it to attach to those in instances of the class since they are going to get called only when the instance holding the fixture is participating in the collision. Most of the code for all this is in Contact.Update() - have a look - might help clear up some issues and shows how the two approaches are mixed and matched.

Jul 29, 2012 at 3:59 PM
Edited Jul 29, 2012 at 4:04 PM

Thank you sir. I think that helped clarify the two implementations. I started using OnCollision/OnSeparation (Farseer style), but since the Farseer site says to refer to Box2D documentation since its a port over, I started looking into how collision detection is done in Box2d and got confused and thought the collision implementation differed due to programming language.

So in my initial code sample, I could in my Game1.cs file > Initialize() method do this to setup my Sprite classes to hook into the World instance's Begin/EndContact and Pre/PostSolve events

Sample: 

//inside Initialize() method of Game1.cs class
this.world.ContactManager.BeginContact += new BeginContactDelegate(BeginContact);
this.world.ContactManager.EndContact += new EndContactDelegate(EndContact);
this.world.ContactManager.PreSolve += new PreSolveDelegate(PreSolve);
this.world.ContactManager.PostSolve += new PostSolveDelegate(PostSolve);

//OR should I hook them using 
this.world.ContactManager.BeginContact = MySpriteClass.BeginContact; //I think its the same thing as above, but shorthand in lamda, correct me if I'm wrong

//Stubs for my methods for those events...Inside MySpriteClass
public static bool BeginContact(Contact contact) { /*do something here...*/ return true; }
public static void EndContact(Contact contact) { /*do something here...*/ }
public static void PreSolve(Contact contact, ref Manifold oldManifold) { /*do something here...*/ }
public static void PostSolve(Contact contact, ContactConstraint impulse) { /*do something here...*/ }

I was not aware that Farseer also provided BeforeCollision/AfterCollision events on Fixtures. Looking at Body.cs, there were only two events present. 

Now that I have a better understanding of the two collision implementations, could you please advise or point me how to use 'Contact' to calculate collision impulse/force on impact between two fixtures inside the OnCollision event.