Collision problem, EndContact for bodies that are removed...

Discuss issues specific to using Box2D on the iPhone
KAMIKAZE
Posts: 17
Joined: Thu Jun 28, 2012 1:57 am

Collision problem, EndContact for bodies that are removed...

Postby KAMIKAZE » Thu Aug 08, 2013 3:23 pm

Hello,

I've implemented simple strategy to get collision of bodies in my game.
Here is my ContactListener class

Code: Select all

struct MyContact {
    b2Fixture *fixtureA;
    b2Fixture *fixtureB;
    bool operator==(const MyContact& other) const
    {
        return (fixtureA == other.fixtureA) && (fixtureB == other.fixtureB);
    }
};

class ContactListener : public b2ContactListener {

public:
    std::vector<MyContact>_contacts;

    bool bottom_contacted;
    ContactListener();
    ~ContactListener();
   
   virtual void BeginContact(b2Contact* contact);
   virtual void EndContact(b2Contact* contact);
   virtual void PreSolve(b2Contact* contact, const b2Manifold* oldManifold);   
   virtual void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse);
   
};



Code: Select all

ContactListener::ContactListener() : _contacts() {
}

ContactListener::~ContactListener() {
}

void ContactListener::BeginContact(b2Contact* contact) {

    MyContact myContact = { contact->GetFixtureA(), contact->GetFixtureB() };
    _contacts.push_back(myContact);
   
    b2Fixture* fixtureA = contact->GetFixtureA();
   b2Fixture* fixtureB = contact->GetFixtureB();
   // Sprites that collided
   CCNode* actorA = (CCNode*)fixtureA->GetBody()->GetUserData();
   CCNode* actorB = (CCNode*)fixtureB->GetBody()->GetUserData();

    if (actorA.tag==ACTOR_TAG && actorB.tag==TAG_BOTTOM_WALL) {
        bottom_contacted = YES;
    } else {
        if (actorB.tag==ACTOR_TAG && actorA.tag==TAG_BOTTOM_WALL) {
            bottom_contacted = YES;
        }
    }
}

void ContactListener::EndContact(b2Contact* contact) {

    b2Fixture* fixtureA = contact->GetFixtureA();
   b2Fixture* fixtureB = contact->GetFixtureB();
   // Sprites that collided
   CCNode* actorA = (CCNode*)fixtureA->GetBody()->GetUserData();
   CCNode* actorB = (CCNode*)fixtureB->GetBody()->GetUserData();
   
    if (actorA.tag==ACTOR_TAG && actorB.tag==TAG_BOTTOM_WALL) {
        bottom_contacted = NO;
    } else {
        if (actorB.tag==ACTOR_TAG && actorA.tag==TAG_BOTTOM_WALL) {
            bottom_contacted = NO;
        }
    }
   
    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);
    }
}

void ContactListener::PreSolve(b2Contact* contact, const b2Manifold* oldManifold) {
   
}

void ContactListener::PostSolve(b2Contact* contact, const b2ContactImpulse* impulse) {
   
}


I want to check, if my game actor colliding with the floor. So, I'm using tag to check colliding objects, in my afterStep method (I'm using fixed timestep - http://stackoverflow.com/questions/6982 ... d-timestep ) I'm checking variable bottom_contacted and do some stuff, all works fine...

Now, in my game, the player collects coins, they are box2d dynamic bodies with GravityScale=0 and also flagged as sensor "isSensor=Yes".
In afterStep method I'm checking if actor collides with the coin, and push coin to toDestroy array, usual way..
But I'm getting BAD_ACCESS for code:

Code: Select all

if (actorA.tag==ACTOR_TAG && actorB.tag==TAG_BOTTOM_WALL) {
or

Code: Select all

 if (actorB.tag==ACTOR_TAG && actorA.tag==TAG_BOTTOM_WALL) {

in method

Code: Select all

void ContactListener::EndContact(b2Contact* contact) {


As I understand, this happens because in afterStep method I''m removing bodies, so in EndContact method there is a death pointers to objects, but how I can avoid this?
What the best way to detect collision in EndContact along with removing some other bodies in BeginContact.

irresistible force
Posts: 1991
Joined: Tue Jun 24, 2008 8:25 pm
Location: Tokyo
Contact:

Re: Collision problem, EndContact for bodies that are remove

Postby irresistible force » Thu Aug 08, 2013 4:19 pm

GetUserData can return NULL, so you should check if the pointer is actually a real pointer before trying to use it.
If you destroy the thing you previously put into the user data, you could also set the user data to NULL to make sure you know it is invalid.

KAMIKAZE
Posts: 17
Joined: Thu Jun 28, 2012 1:57 am

Re: Collision problem, EndContact for bodies that are remove

Postby KAMIKAZE » Wed Nov 13, 2013 9:45 am

Aha! Here it is! After removing coins I set it userdata to nil: body->SetUserData(nil); and in EndContact I do a check - if (actorA==nil || actorB==nil) return;

Thank you! Image


Last bumped by KAMIKAZE on Wed Nov 13, 2013 9:45 am.


Return to “iPhone”



Who is online

Users browsing this forum: No registered users and 2 guests