Box2D Forums

It is currently Mon May 20, 2013 10:28 am

All times are UTC - 8 hours [ DST ]




Post new topic Reply to topic  [ 7 posts ] 
Author Message
PostPosted: Sat Aug 11, 2012 5:35 pm 
Offline

Joined: Sat Aug 04, 2012 10:39 am
Posts: 13
Hello Box2D community,

I've hit a bit of a snag. I've got 2 fixtures which I'm able to detect but once the initial detection has been made, I want to stop collision on those 2 objects. It's comparable to dropping a box onto the ground and once the box hits the ground, I would like the initial contact to be noted but all further occurrences between those 2 specific objects to stop. What I'm getting however, is constant detection between the 2 objects as my ContactListener container holding the 2 fixtures continues to loop away. This is what I have in my contact listener:

Code:
void MyContactListener::BeginContact(b2Contact* contact) {
    MyContact myContact = { contact->GetFixtureA(), contact->GetFixtureB() };
    _contacts.push_back(myContact);
}

void MyContactListener::EndContact(b2Contact* contact) {
    MyContact myContact = { contact->GetFixtureA(), contact->GetFixtureB() };
    std::vector<MyContact>::iterator pos;
    pos = std::find(_contacts.begin(), _contacts.end(), myContact);
    if (pos != _contacts.end()) {
        _contacts.erase(pos);
    }
   
    b2Filter filter1 = myContact.fixtureA->GetFilterData();
    b2Filter filter2 = myContact.fixtureB->GetFilterData();
    filter1.groupIndex = -8;
    filter2.groupIndex = -8;
    myContact.fixtureA->SetFilterData(filter1);
    myContact.fixtureB->SetFilterData(filter2);
}


I thought by setting filter data to -8 on both fixtures at the end of the Contact, I'd be able to achieve what I'm after but this doesn't work. Some guidance on this would be much appreciated.


Top
 Profile  
 
PostPosted: Sat Aug 11, 2012 11:47 pm 
Offline

Joined: Tue Jun 24, 2008 8:25 pm
Posts: 1515
Location: Tokyo
Calling myContact.SetEnabled(false) should stop the contact from having a collision response.
Information from the fixtures is copied into the contact when it begins, so changing the fixture properties after that will not make a difference during the current contact's lifespan. The lifespan of a contact does not necessarily finish when you get an EndContact event, because the AABB of the fixtures may still be overlapping. See this thread too: viewtopic.php?f=4&t=8686#p36897


Top
 Profile  
 
PostPosted: Sun Aug 12, 2012 4:42 am 
Offline

Joined: Sat Aug 04, 2012 10:39 am
Posts: 13
Thanks for the reply, that's cleared a few things up but has also made me rethink whether my approach isn't quite right.

My issue seems to be to do with the fact that upon every timestep in my Begin method, I'm storing a b2Contact in a vector. This means that if I have 10 points of contact, I'll have 10 contact objects in my vector which in my update method, I'm iterating through which isn't what I'm after. This is despite erasing the contents in my End method (which I guess makes sense the objects are just re-added again in Begin(). Instead, what I'm after is the following:

    Contact between 2 fixtures (A, B) is made - contact noted and relevant action taken
    Contact between next 2 fixtures (C, D) is made - contact noted and relevant action taken
    Contact between next 2 fixtures (E, F) is made - contact noted and relevant action taken

However, what's happening for me at the moment is this:

    Contact between 2 fixtures (A and B) is made - contact noted and relevant action taken
    Contact between 2 previous fixtures + next 2 fixtures (A, B and C, D) is made - contact noted but previous contact is also noted (not good)
    Contact between 4 previous fixtures + next 2 fixtures (A,B C,D and E, F) is made - contact noted but previous 2 contacts are also noted
    etc...

So I was thinking there's a few ways I can go about this but I'm not sure which would be most suitable (if any?),

1. Maybe I could adjust the bounding box so that when contact is made, I somehow offset the contact by 1-2 pixels so the fixtures are not touching anymore which will stop my vector picking up these contacts
2. Delete all the contents from the vector only keeping the last b2Contact object (which I presume would contain the 'latest' contact object?) - this seems a bit dirty
3. Scrap the vector and take a different approach though I'm not sure what this would be.

Any other suggestions or advice would be great, I feel like I'm missing something here. :|


Top
 Profile  
 
PostPosted: Sun Aug 12, 2012 8:36 am 
Offline

Joined: Tue Jun 24, 2008 8:25 pm
Posts: 1515
Location: Tokyo
Although you can keep references to contacts (ie. in a vector as you are doing) without causing any problems, I don't think contacts are really intended to be something that the user deals with much outside the contact listener functions. You can modify them a little (eg. SetEnabled, SetTangentVelocity etc) but mostly they serve only as a temporary reference to link between two overlapping fixtures. Opinions may differ here and I guess it doesn't matter all that much, but I would probably try to keep only the necessary information about what the contact actually means for your game, rather than the contact itself. For example if you have a player and a patch of lava on the ground, the player only need know when he is touching the lava, and the patch of ground doesn't need to know anything. So all you need there is a flag in the player which gets turned off and on by the Begin/EndContact events. At the other end of the scale there are more complex things like keeping track of a continuous contact, with position and force info, for example if you wanted to draw smoke or dust coming from a wheel rotating against the ground. In this case you need much more information, but you can get it every frame in Pre/PostSolve. Storing a contact usually doesn't help a lot because things will almost always change in the next frame, and the contact listener events will tell you all you need to know about the change.


Top
 Profile  
 
PostPosted: Mon Aug 13, 2012 7:48 am 
Offline

Joined: Tue Sep 25, 2007 2:22 pm
Posts: 482
If TSBox2DBody::HandleBeginContact (my b2Body::m_userData base class) returns false for either body, then the contact is disabled. You need to keep that contact disabled each frame, so take a look:

Code:
bool TSBox2DBody::HandleBeginContact(b2Contact* contact) {
    return true;
}

void TSBox2DBody::HandlePreSolve(b2Contact* contact) {
}

void TSBox2DBody::BeginContact(b2Contact* contact) {
   TSBox2DBody* bA = getUserDataA(contact);
   TSBox2DBody* bB = getUserDataB(contact);
   
   TSBox2D* box2D = NULL;
   if(bA) box2D = bA->box2D;
   if(bB) box2D = bB->box2D;
   
    bool enableContact = true;
   if(bA) enableContact &= bA->HandleBeginContact(contact);
   if(bB) enableContact &= bB->HandleBeginContact(contact);

   if(box2D && contact->GetFixtureA()->GetBody() != box2D->groundBody && contact->GetFixtureB()->GetBody() != box2D->groundBody && !enableContact) {
      behaviorForContact[contact] = false;
      contact->SetEnabled(false);
   } else {
      behaviorForContact[contact] = true;
      contact->SetEnabled(true);
   }
}

void TSBox2DBody::HandleEndContact(b2Contact* contact) {
}

void TSBox2DBody::EndContact(b2Contact* contact) {
   TSBox2DBody* bA = getUserDataA(contact);
   TSBox2DBody* bB = getUserDataB(contact);
         
   if(bA) bA->HandleEndContact(contact);
   if(bB) bB->HandleEndContact(contact);
   
   // $$$ remove key!
   behaviorForContact.erase(contact);
}

void TSBox2DBody::PreSolve(b2Contact* contact, const b2Manifold* oldManifold) {
   contact->SetEnabled(behaviorForContact[contact]);
   
   TSBox2DBody* bA = getUserDataA(contact);
   TSBox2DBody* bB = getUserDataB(contact);
   
   if(bA) bA->HandlePreSolve(contact);
   if(bB) bB->HandlePreSolve(contact);
}
      
void TSBox2DBody::PostSolve(b2Contact* contact, const b2ContactImpulse* impulse) {
}


Top
 Profile  
 
PostPosted: Tue Aug 14, 2012 2:11 pm 
Offline

Joined: Sat Aug 04, 2012 10:39 am
Posts: 13
Thanks for the replies iforce/pTymN, I really appreciate it. I managed to get the desired result by checking to see whether there were any actions running on my sprites (I use 'actions' in order to move sprites and their associated box2d bodies/fixtures around). If there were zero actions running on the sprites then I could safely assume that the sprites have come to a stop and I can simply skip the function which is invoked when a collision is detected. I'll see how this method holds up as I develop further. If its not suitable, I'll reiterate over the ideas suggested here.

Thanks again, I have a better understanding of contact objects and contact listeners now.


Top
 Profile  
 
PostPosted: Tue Aug 14, 2012 3:17 pm 
Offline

Joined: Tue Sep 25, 2007 2:22 pm
Posts: 482
pac-man, your system sounds interesting. We could get into a whole new discussion about timesteps and the difference between how time is handled in update vs render, how to use keyframed animations to drive a game object state machine in Box2D, how to create an efficient predictive AI...


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 7 posts ] 

All times are UTC - 8 hours [ DST ]


Who is online

Users browsing this forum: No registered users and 4 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group