oopology
oopology

Reputation: 1072

body null when accessed from another method

I have a contact listener that handles contact between two box2d bodies. I am accessing the bodies from the Contacter in the HelloWorldLayer since box2d recommends that contacting bodies should be saved and changes implemented after the timestep. Please see the code below:

Contacter.h:

#import "CCPhysicsSprite.h"

@interface Contacter : CCPhysicsSprite {

}

@property(nonatomic, assign) NSMutableArray* arrayOfBodies;
@property(nonatomic, assign) CCPhysicsSprite* spriteToDestroy;


-(void)physicsSpritesContact:(CCPhysicsSprite*)onePhysicsSprite otherSprite:(CCPhysicsSprite*)twoPhysicsSprite;

@end

Contacter.mm:

#import "Contacter.h"
#import "Box2D.h"

@implementation Contacter

@synthesize arrayOfBodies = _arrayOfBodies;
@synthesize spriteToDestroy = _spriteToDestroy;

-(void)destroyBodies:(b2Body*)body   {
    _arrayOfBodies = [[NSMutableArray alloc] init];
    NSValue *bodyValue = [NSValue valueWithPointer:body];
    [_arrayOfBodies addObject:bodyValue];
}

-(void)physicsSpritesContact:(CCPhysicsSprite*)onePhysicsSprite otherSprite:   (CCPhysicsSprite*)twoPhysicsSprite; {
int firstTag = onePhysicsSprite.tag;
int secondTag = twoPhysicsSprite.tag;

if (((firstTag == 90) && (secondTag == 101 )) || ((firstTag == 101) && (secondTag == 90))) {

    if (tag1 == 90) {
        [self destroyBodies:onePhysicsSprite.b2Body];// adds body to array to be destroyed
        spriteToDestroy = onePhysicsSprite; // taking note of sprite to be destroyed

    }
    else if (tag2 == 90)   {
        [self destroyBodies:twoPhysicsSprite.b2Body];
        spriteToDestroy = twoPhysicsSprite;
    }
}

}

The following method within HelloWorldLayer.mm is called in the update method:

-(void)removeDestroyedBodiesAndSprites  {
bodyContact = [Contacter node];    
if ([bodyContact arrayOfBodies]) {


for (NSValue* bodyValue in [bodyContact arrayOfBodies]) {
    b2Body *removeBody;
    removeBody = (b2Body*)[bodyValue pointerValue];

    world->DestroyBody(removeBody);
    removeBody = NULL;
    [self removeChild:[bodyContact spriteToDestroy]];
       }
    }
}

There is contact but the sprite is not removed and body is not destroyed in removeDestroyedBodiesAndSprites. After testing with a CCLOG I found that the for loop was not satisfied meaning that the arrayOfBodies could be null. Which is surprising since the contact was established. I would appreciate your assistance.

UPDATED

Below is the contact listener:

TestContactListener.h:

#import <Foundation/Foundation.h>
#import "cocos2d.h"
#import "Box2D.h"
#import "GameObjects.h"
#import "Contacter.h"


class TestContactListener : public b2ContactListener    {
public:
    Contacter* contacter;

    void BeginContact(b2Contact* contact);
};

TestContactListener.mm:

#import "TestContactListener.h"

void TestContactListener:: BeginContact(b2Contact *contact)
{
    contacter = [Contacter node];

    b2Fixture       *fixtureA = contact->GetFixtureA();
    b2Fixture       *fixtureB = contact->GetFixtureB();
    b2Body          *fixtureABody = fixtureA->GetBody();
    b2Body          *fixtureBBody = fixtureB->GetBody();

    CCPhysicsSprite* physicsSprite = (CCPhysicsSprite*)fixtureABody->GetUserData();
    CCPhysicsSprite* physicsSprite2 = (CCPhysicsSprite*)fixtureBBody->GetUserData();

    [contacter physicsSpritesContact:physicsSprite otherSprite:physicsSprite2];

}

Upvotes: 1

Views: 114

Answers (2)

Lorenzo Linarducci
Lorenzo Linarducci

Reputation: 541

Move this from the destroyBodies method to an init method, so it is only called once:

_arrayOfBodies = [[NSMutableArray alloc] init];

Upvotes: 1

CodeSmile
CodeSmile

Reputation: 64477

Take a good look at your destroyBodies method. You create a new array, replacing any existing array, every time you call it. Therefore you will only destroy the last body you passed in to that method.

If you are not using ARC you'll also leak all the replaced arrays.

Upvotes: 0

Related Questions