Page 1 of 2

<SOLVED>Collisions not coliding

Posted: Thu May 10, 2012 2:53 pm
by jcmeyer5
I am trying to set up my collision handlers. I have one set up to test with, but nothing happens. Essentially, this handler handles an inert object being dropped on the player's head (one shape on a complex object). I am using PhysicsEditor to add my bodies and shapes, and the latest Objective-Chipmunk. So... here is the code I have so far.

Code: Select all

// rocks hitting the player
-(void)Begin_Player_Inert:(cpArbiter *)arbiter space:(ChipmunkSpace*)space {
	CCLOG(@"PLAYER INERT COLLISION!");
	CHIPMUNK_ARBITER_GET_SHAPES(arbiter, player, inert);
	applyPlayerDamage(player.data, arbiter, self);
}

-(void)addCollisionHandlers {
    [space addCollisionHandler:self typeA:[Player class] typeB:[Inert class] 
    begin:@selector(Begin_Player_Inert:space:) preSolve:nil postSolve:nil separate:nil];
}
So what happens... is nothing. I am trying to follow the examples in Angry Chipmunk for collision handling while still taking advantage of the relative ease of using Physics Editor. I want the callback when the collision occurs, so I am using the begin: callback. As far as I can tell, the collision isnt making it out of the collision handler as it never calls the callback. I am guessing it has something to do with how I am specifying typeA and typeB. I wanted to use PhysicsEditor collision_type field, but it is an integer incompatible with the Obj-Chip id collision_type field. So... what am I missing?

Re: Collisions... nothing happening

Posted: Thu May 10, 2012 3:52 pm
by slembcke
So Objective-Chipmunk uses object references instead of integers as it's much much easier to use unique and accessible values that way.

You can still use integers for collision types though, just cast the integer to id. (Note, this doesn't work with ARC)

Code: Select all

 [space addCollisionHandler:self typeA:(id)5 typeB:(id)6 ...];

Re: Collisions... nothing happening

Posted: Thu May 10, 2012 9:23 pm
by jcmeyer5
Okay, I have tossed out my complex scenario for a basic box and circle scenario just so I can learn this. Here is my box class:

Code: Select all

-(id)initAtPos:(cpVect)pos {
	//************************************************************************
	self.position = pos;
	
	hitPoints = 1000;
		
	chassis = [ChipmunkCocosBody bodyWithMass:10.0 andMoment:cpMomentForBox(10.0, 100.0, 30.0)];
	ChipmunkPolyShape* mainShape = [ChipmunkPolyShape boxWithBody:chassis width:100.0 height:30.0];

	// assign body position to GameObject
	chassis.pos = self.position;
	mainShape.collisionType = [Box class];
	mainShape.group = self;
	mainShape.layers = 1;

	chipmunkObjects = [[NSArray alloc] initWithObjects:
							 chassis, mainShape, nil];
	
	return self;
}

+(Box*)boxAtPos:(cpVect)pos {
	return [[Box alloc] initAtPos:pos];
}
And my circle class:

Code: Select all

-(id)initWithName:(NSString*)name atPos:(cpVect)pos {
	
	// set objectType to inert
	self.objectType = kTypeInert;
	
	// load sprite frame cache
	[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:@"sprites.plist"];
	// load sprite from 
	CCSprite* sprite = [CCSprite spriteWithSpriteFrameName:name];
	// add sprite to array
	objectSprites = [[NSArray alloc] initWithObjects:sprite, nil];
	
	body = [ChipmunkCocosBody bodyWithMass:5.0 andMoment:cpMomentForCircle(5.0, 12, 12, cpvzero)];
	ChipmunkCircleShape* rock = [ChipmunkCircleShape circleWithBody:body	radius:12 offset:cpvzero];
	// set position of body to provided position
	body.pos = pos;
	// assign body position to GameObject
	self.position = body.pos;
	rock.collisionType = [Rock class];
	rock.group = self;
	rock.layers = 1;

	// load sprites array to synced nodes
	body.syncedNodes = objectSprites;
	
	// load chipmunk objects to chipmunkObjects array
	chipmunkObjects = [[NSArray alloc] initWithObjects:body, rock, nil];
	
	return self;
}

+(Rock*)rockWithName:(NSString*)name atPos:(cpVect)pos {
	return [[Rock alloc] initWithName:name atPos:pos];
}
Here are my collision methods (they don't do anything except tell me they are being executed):

Code: Select all


static inline void applyDamage(Box* box, cpArbiter* arb, GameLayer* self) {
	if(cpArbiterIsFirstContact(arb)){
		// Divide the impulse by the timestep to get the collision force.
		cpFloat impact = cpvlength(cpArbiterTotalImpulse(arb))/FIXED_TIMESTEP;
		CCLOG(@"Impact Value: %f",impact);
	}
}

-(void)begin:(cpArbiter*)arbiter space:(ChipmunkSpace*)space {
	CCLOG(@"COLLISION");
	CHIPMUNK_ARBITER_GET_SHAPES(arbiter, box, rock);
	applyDamage(box.data, arbiter, self);
}

-(void)addCollisionHandlers {
	[space addCollisionHandler:self typeA:[SimpleCar class] typeB:[Rock class] begin:@selector(begin:space:) 
	     preSolve:nil postSolve:nil separate:nil];
}
Now, currently, dropping a circle on the box results in a collision call (with impact of 0.000), but the circle drops right through the box. If I don't call the handlers (comment out the [self addCollisionHandlers]), the circles bounce off the box as they should. Again, I am trying to model this off of the Angry Chipmunks demo, but for the life of me, I can't get it to work. What am I missing?

Re: Collisions... nothing happening

Posted: Thu May 10, 2012 10:39 pm
by jcmeyer5
Eureka!! I found it. My "begin" callback needed to be a BOOL return and not a void return. Once I fixed that, I started getting impact values and the circles bounced off properly.

Re: <SOLVED>Collisions not coliding

Posted: Fri May 11, 2012 7:04 am
by jcmeyer5
I was able to migrate the collision code back to my original classes without incident. Sweetness!

Re: <SOLVED>Collisions not coliding

Posted: Fri May 11, 2012 7:37 am
by slembcke
Also, cpArbiterTotalImpulse() (and other functions that deal with impact values) must be called from a post-solve callback. Otherwise the values you are asking for haven't been calculated yet.

Re: <SOLVED>Collisions not coliding

Posted: Fri May 11, 2012 9:56 am
by jcmeyer5
Just figured that out too, as I was getting intermittent values. Moving it to the postSolve gives the results I am looking for. Thanks for the help. I am going to do a search to see if I can find more details on the differences in collision callbacks.

Re: <SOLVED>Collisions not coliding

Posted: Fri May 11, 2012 1:43 pm
by jcmeyer5
Okay, another snag...

I am now trying to remove rocks that hit the player. I am trying to do this in the separate callback. Problem is, I am getting a "cannot remove body that was not added to the space (removed twice maybe?)" error. Also, the second rock appears to generate more than one collision before a removal is attempted... could that be part of it? More specifically, here is the console output:

Code: Select all

Initializing cpSpace - Chipmunk v6.0.3 (Debug Enabled)
Compile with -DNDEBUG defined to disable debug mode and runtime assertion checks
2012-05-11 14:36:15.234 ChipTest[26965:10a03] Spawning...
2012-05-11 14:36:15.235 ChipTest[26965:10a03] GameObject added. // player
2012-05-11 14:36:15.236 ChipTest[26965:10a03] cocos2d: Frame interval: 1
2012-05-11 14:36:15.237 ChipTest[26965:10a03] cocos2d: surface size: 1024x768
2012-05-11 14:36:15.394 ChipTest[26965:10a03] Coasting
2012-05-11 14:36:16.453 ChipTest[26965:10a03] cocos2d: CCSpriteBatchNode: resizing TextureAtlas capacity from [5] to [8].
2012-05-11 14:36:19.353 ChipTest[26965:10a03] GameObject added. // rock#1
2012-05-11 14:36:20.186 ChipTest[26965:10a03] POSTSOLVE // rock#1
2012-05-11 14:36:20.186 ChipTest[26965:10a03] Impact Value: 2782.263916 // rock#1
2012-05-11 14:36:20.203 ChipTest[26965:10a03] GameObject removed. // rock#1
2012-05-11 14:36:25.384 ChipTest[26965:10a03] GameObject added. // rock#2
2012-05-11 14:36:26.186 ChipTest[26965:10a03] POSTSOLVE // rock#2
2012-05-11 14:36:26.187 ChipTest[26965:10a03] Impact Value: 1788.794922 // rock#2
2012-05-11 14:36:26.187 ChipTest[26965:10a03] POSTSOLVE  // still rock#2
2012-05-11 14:36:26.187 ChipTest[26965:10a03] Impact Value: 1373.066650 // still rock#2
2012-05-11 14:36:26.188 ChipTest[26965:10a03] POSTSOLVE // still rock#2
2012-05-11 14:36:26.203 ChipTest[26965:10a03] POSTSOLVE // still rock#2
Chipmunk warning: Adding a post-step callback when the space is not locked is unnecessary. Post-step callbacks will not called until the end of the next call to cpSpaceStep() or the next query.
	Failed condition: space->locked
	Source:/tmp/ChipmunkPro-TMP/Chipmunk/src/cpSpaceStep.c:55
2012-05-11 14:36:26.204 ChipTest[26965:10a03] GameObject removed.
Aborting due to Chipmunk error: Cannot remove a body that was not added to the space. (Removed twice maybe?)
	Failed condition: cpSpaceContainsBody(space, body)
	Source:/tmp/ChipmunkPro-TMP/Chipmunk/src/cpSpace.c:394
Here is my collision stuff:

Code: Select all

//**************************************************************************

static inline void applyDamage(Vehicle* vehicle, cpArbiter* arb, GameLayer* self) {
	if(cpArbiterIsFirstContact(arb)){
		// Divide the impulse by the timestep to get the collision force.
		cpFloat impact = cpvlength(cpArbiterTotalImpulse(arb));
		if (impact > 0.0f) CCLOG(@"Impact Value: %f",impact);
	}
}

-(void)postsolveVehicle:(cpArbiter*)arbiter space:(ChipmunkSpace*)space {
	CCLOG(@"POSTSOLVE");
	CHIPMUNK_ARBITER_GET_SHAPES(arbiter, carShape, rockShape);
	applyDamage(carShape.data, arbiter, self);
}

-(void)separateInert:(cpArbiter*)arbiter space:(ChipmunkSpace*)space {
	CHIPMUNK_ARBITER_GET_SHAPES(arbiter, carShape, rockShape);
	[self->space addPostStepBlock:^{ [self remove:rockShape.data]; } key:rockShape.data];
}

-(void)addCollisionHandlers {
	[space addCollisionHandler:self typeA:[Vehicle class] typeB:[Inert class] 
								begin:nil preSolve:nil postSolve:@selector(postsolveVehicle:space:) separate:@selector(separateInert:space:)];
}

//**************************************************************************


Re: <SOLVED>Collisions not coliding

Posted: Fri May 11, 2012 10:21 pm
by slembcke
Aha! I think that is the same as a bug that I just fixed. It's... a little complicated to explain why it happens though. It has to do with separate callbacks that can be triggered immediately when removing objects, and scheduling post-step callbacks within them. Try updating to the latest code out of Git and see if your problem goes away.

Re: <SOLVED>Collisions not coliding

Posted: Sat May 12, 2012 2:59 pm
by jcmeyer5
I will try the code Monday. I did find a work around with switching the callbacks. I put rock removal as postSolve and damage as separate. Not sure if that switch has ramifications that I have not yet considered, but it appears to be working well.