Sensors not reporting contact

General discussion about the R.U.B.E editor
Post Reply
therealcos
Posts: 16
Joined: Tue Aug 20, 2013 7:30 am

Sensors not reporting contact

Post by therealcos »

I have a few sensor fixtures in my world that move with the hero, and I'm trying to set them up so that they report a contact whenever they're overlapping with static bodies called "planets".

I set up a standard contact listener (which correctly reports other contacts within the world) and from within the world layer, I iterate through all the contacts and check to see if fixtures A and B of each contact are either a sensor or planet - if so, I set a boolean to true, as shown below:

Code: Select all

    std::vector<MyContact>::iterator pos;
    for(pos = contactListener->contacts.begin(); pos != contactListener->contacts.end(); ++pos) {

        MyContact contact = *pos;

        for (int i=0; i < planets.size(); i++){
            
            b2Fixture* p = planets[i]->GetFixtureList();

            if ((contact.fixtureA == sensor->GetFixtureList() && contact.fixtureB == p) ||
                (contact.fixtureA == p && contact.fixtureB == sensor->GetFixtureList())){
                sensorOn = true;
            }
       }
    }
This doesn't seem to work, since the boolean is false even when a planet is overlapping with a sensor. Do sensor fixtures report contacts in the same way as normal fixtures? Or is there some other way I need to do this from within the contact listener class?
iforce2d
Site Admin
Posts: 861
Joined: Sat Dec 22, 2012 7:20 pm

Re: Sensors not reporting contact

Post by iforce2d »

I think what we are considering to be a 'standard contact listener' is a bit different. Typically the contact listener has a BeginContact function inside which you will check what the two fixtures are, and take some appropriate action:

Code: Select all

void BeginContact(b2Contact* contact) {
    b2Fixture* fixtureA = contact->GetFixtureA();
    b2Fixture* fixtureB = contact->GetFixtureB();

    ... if sensor touched planet, let the planet know ...
    ... if bullet touched enemy, make an explosion ...
    ... etc ...
}
I am not aware of the contact listener class having any 'contacts' member, and whatever this 'MyContact' class is, I have no idea.

Ok that's not quite true... I have seen similar approaches to this many times before, so I guess somebody must have written a tutorial or something that recommended to duplicate and store the information about contacts, and then loop through that every frame to use it. In my opinion this is a bad idea, and I think it is unfortunate that this method has spread over the net so much. There is no need to duplicate the same information when in most cases the vast majority of contacts are of no interest to the game logic, and this method will scale badly for scenes with thousands of contacts (especially if that 'contacts' variable is a std::vector). It also makes things unnecessarily complex to manage, which I think is the root of your problem here.

To answer your other question, yes, contacts for sensors will report BeginContact and EndContact events in the normal way. But since there is no collision response necessary they don't generate PreSolve/PostSolve calls, so they are a bit different in that respect.

Another thing that can occasionally cause trouble here is that if you have just added a new fixture to the world, you might need to run one Step of the world before the BeginContact event shows up.
iforce2d
Site Admin
Posts: 861
Joined: Sat Dec 22, 2012 7:20 pm

Re: Sensors not reporting contact

Post by iforce2d »

oh... now that I take a closer look at your code, I see you are only looking at one fixture of the bodies involved, because the GetFixtureList function only returns the first fixture in the list of fixtures attached to a body. If your hero body has more than one fixture, then you really should be checking all of them, not just the first one. You can iterate over the fixtures of a body like:

Code: Select all

for (b2Fixture* f = body->GetFixtureList(); f; f = f->GetNext())
{
    //do something with the fixture 'f'
}
therealcos
Posts: 16
Joined: Tue Aug 20, 2013 7:30 am

Re: Sensors not reporting contact

Post by therealcos »

I actually have a few sensor fixtures on the same body that I wanted to check individually for contact, but even when I iterate through all the fixtures in the body, it still doesn't work.

I modeled my contact listener after the one used in this tutorial: http://www.raywenderlich.com/28606/how- ... ial-part-2

Basically, all the contacts processed by my contact listener are put into (or deleted from) a member array called 'contacts' as shown below:

Code: Select all


void ContactListener::BeginContact(b2Contact* contact) {

    MyContact myContact = { contact->GetFixtureA(), contact->GetFixtureB() };
    contacts.push_back(myContact);
}

void ContactListener::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);
    }
}

Then these contacts are accessed from the world layer code instead of from within the contact listener, as shown in the code in my first post. This method works all other contacts except the sensors for some reason. I can try to accomplish this from within BeginContact/EndContact, but you think it wold make any difference?
therealcos
Posts: 16
Joined: Tue Aug 20, 2013 7:30 am

Re: Sensors not reporting contact

Post by therealcos »

Got it working! The problem was that I was updating the sensor body/fixtures with a SetTransform from within the update method so that it would follow the hero's position. Every time the sensor was in motion (i.e. every time its position was being updated) it wouldn't read the contact.

To fix this I just got rid of the SetTransform and put a distance joint between the hero and sensor.

Thanks for all your help!
iforce2d
Site Admin
Posts: 861
Joined: Sat Dec 22, 2012 7:20 pm

Re: Sensors not reporting contact

Post by iforce2d »

If the sensor is supposed to move with the hero body, you can just attach it to the hero body directly. That way you would not need to use SetTransform or a distance joint.
Post Reply