godel9
godel9

Reputation: 7390

Filtering collisions in Chipmunk for trapped bodies

Background

Issue

I've recently added code to play a sound whenever the balls collide with each other or with a wall, which I'm doing inside a postSolve callback:

static void postSolve(cpArbiter *arb, cpSpace *space, cpDataPointer userData)
{
    GameLayer *layer = (__bridge GameLayer *)userData;
    [layer collisionHandler:arb];
}

-(void) collisionHandler:(cpArbiter*)arb
{
    if(cpArbiterIsFirstContact(arb)) {
        [[SimpleAudioEngine sharedEngine] playEffect:kCollisionEffectFilename];
    }
}

Here's the problem... When I drag a ball into a wall, it generates a very large number of collisions, even when filtering on cpArbiterIsFirstContact, and it sounds terrible. It appears that the ball is bouncing off the wall, being driven back into wall by the constraint, rinse, and repeat. I'd like to play the collision sound only once or twice in this scenario.

Things I've tried that don't seem to work...

Question

Is there a way to filter collisions for trapped bodies?

Upvotes: 0

Views: 352

Answers (2)

slembcke
slembcke

Reputation: 1409

So you are using a constraint to drag the ball around, and the ball is elastic correct? Have you tried tweaking the constraint parameters at all? If the constraint has a lower maxForce, the chance for oscillations would drop significantly.

Another thing that can help is to increase the space's collision slop (how much shapes are allowed to overlap). The default value is 0.1 (in whatever scale you are using), but increasing it to a pixel or so can help this sort of thing significantly without being very visible.

Upvotes: 1

CodeSmile
CodeSmile

Reputation: 64477

A simple and effective solution is to avoid playing the sound in quick succession.

When the ball contacts with the wall, check if the ball's "last contact" timer is lower than the current time. If so, play the sound and set the ball's "last contact" time to the current time plus x, where x is the timeout duration the sound shouldn't play again (ie 0.5 seconds).

In cocos2d-iphone you can add up an update method's deltaTime to keep track of time. There are also a number of ways to get system time, for example [NSDate date].timeIntervalSince1970 gives you the current number of seconds since 1970. I know, seems ridiculous, but if you get that number again sometime later, and subtract the previous number of seconds you get the difference in seconds, that's all that counts.

Upvotes: 1

Related Questions