cpBody Rotation not consistent

Official forum for the Chipmunk2D Physics Library.
Post Reply
varunsingh
Posts: 4
Joined: Wed Jul 20, 2011 8:15 am
Contact:

cpBody Rotation not consistent

Post by varunsingh »

Hi,
This is my first iPhone application which is a game using Chipmunk Engine. It has 7 triangular shaped objects and a game character. The triangles are arranged one above the other at constant distance. The game character jumps from one triangle to another and with the help of accelerometer, the user controls the horizontal axial movement. The triangles may rotate if the character jumps near to the vertex.
The mass of the character is 200 units whereas the mass of each triangle is 1 unit. Hence the triangles are supposed to be very fragile and sensitive to rotation. The problem is that the first four triangles behave the way they should. They are very fragile and sensitive to rotation. But as the character goes up, the triangles become lesser sensitive and upon collision they vibrate more and rotate less. Though all the triangles have same mass, still they behave inconsistently. Please help me figuring out why is it happening and how can it be rectified?

Code: Select all

//Code for Triangular body's physics


-(void) createTriangularBodies {
	
	//A staticBody is created and joined to a normal 
	//body added to the space. Both the bodies are 
	//joined by PinJoint. The normal body's shape is triangular.
	//the vertices are given by mLeftVertex, mRightVertex, 
	//mBottomVertex.
	mStaticBody = cpBodyNew(INFINITY, INFINITY);
	mStaticBody->p = cpv(mCentroid.x, mCentroid.y);
	mBody = cpBodyNew(TRIANGLE_MASS, INFINITY);
	mBody->p = cpvzero;

	mRotatingConstraint = cpPinJointNew(mStaticBody, mBody, cpvzero, mCentrePosition);
	cpSpaceAddConstraint(mSpace, mRotatingConstraint);
	mBody->velocity_func = cpBodyZeroGravityUpdateVelocity;
	cpSpaceAddBody(mSpace, mBody);
	
	cpVect verts[] = {mLeftVertex, mRightVertex, mRightVertex, mBottomVertex, mBottomVertex, mLeftVertex};
	mShape = cpPolyShapeNew(mBody, 6, verts, cpvzero);
	
	cpBodySetMoment(mBody, cpMomentForPoly(TRIANGLE_MASS, 6, verts, cpvzero));
	
	mShape->e = 0.8f;
	mShape->u = 0.5f;
	mShape->collision_type = TRIANGLE_COLLISION;
	mShape->data = self;
	cpSpaceAddShape(mSpace, mShape);
}

//Creates the Character's Physics

-(void) createCharacterBodies {
	mBody = cpBodyNew(CHARACTER_MASS, INFINITY);
	mBody->p.x = self.position.x;
	mBody->p.y = self.position.y;
	
	cpSpaceAddBody(mSpace, mBody);
	mShape = cpCircleShapeNew(mBody, 10.0f, cpvzero); 
	
	mShape->e = 0.8f;
	mShape->u = 0.5f;
	mShape->collision_type = CHARACTER_COLLISION;
	mShape->data = self;
	cpSpaceAddShape(mSpace, mShape);	
}

//Game's Class. Uses Character and Triangular bodies to build the game.

drawSpaceOptions options = {
	1,//Draw Hash
	1,//Draw BBoxes
	1,//Draw Shapes
	4.0f,//Collision Point Size
	4.0f,//Body Point Size
	1.5f//Line Thickness
};

static void
eachShape(void *ptr, void* unused)
{

	Experimental *this = (Experimental *) unused;
	cpVect accel = [this mAccel];
	cpShape *shape = (cpShape*) ptr;
	CCSprite *sprite = shape->data;
	cpBody *body = shape->body;
	if ([sprite isKindOfClass:[Character class]]) {
		
		//accel has the accelerometer's values as cpVect.
		//it uses the x component to maneuver the character horizontally.
		if (body->p.x + 10 > 320) {
			body->p.x = 10 + accel.x * 10;
		}
		else if (body->p.x - 10 < 0) {
			body->p.x = 320 - 10 + accel.x * 10;
		}
		else {
			body->p.x = body->p.x + accel.x * 10;
		}
	}
	[sprite setPosition:body->p];			
	[sprite setRotation: (float) CC_RADIANS_TO_DEGREES( -body->a )];
}

static void
characterTrianglePostStepJump(cpSpace *space, void *key, void *data);
static int
characterTriangleBegin(cpArbiter *arb, struct cpSpace *space, void *data) {
	cpShape *characterShape, *triangleShape;
	cpArbiterGetShapes(arb, &characterShape, &triangleShape);
	cpBody *characterBody = characterShape->body;
	//Avoids collision if the character is jumping up.
	if (characterBody->v.y > 0) {
		return 0;
	}
	return 1;
}

static int
characterTrianglePreSolve(cpArbiter *arb, struct cpSpace *space, void *data) {
	return 1;
}

static int
characterTrianglePostSolve(cpArbiter *arb, struct cpSpace *space, void *data) {
	Experimental *this = (Experimental *)data;
	cpSpace *cSpace = [this mSpace];
	cpShape *characterShape, *triangleShape;
	cpArbiterGetShapes(arb, &characterShape, &triangleShape);
	cpSpaceAddPostStepCallback(cSpace, &characterTrianglePostStepJump, characterShape, data);
	return 1;
}

static int
characterTriangleSeparate(cpArbiter *arb, struct cpSpace *space, void *data) {
	return 1;
}

static void
characterTrianglePostStepJump(cpSpace *space, void *key, void *data) {
	cpShape *characterShape = (cpShape *) key;
	cpBody *characterBody = characterShape->body;
	if (characterBody->v.y > 0) {
		characterBody->v.y = 200.0f;
	}
}
		

+(id) scene
{
	// 'scene' is an autorelease object.
	CCScene *scene = [CCScene node];
	
	// 'layer' is an autorelease object.
	Experimental *layer = [Experimental node];
	
	// add layer as a child to scene
	[scene addChild: layer];
	
	// return the scene
	return scene;
}

-(id) init {
	
	if (self == [super init]) {
		self.isAccelerometerEnabled = YES;
		cpInitChipmunk();
		mSpace = cpSpaceNew();
		mSpace->gravity = cpv(0, -200);
		mSpace->elasticIterations = mSpace->iterations;
		cpSpaceResizeStaticHash(mSpace, 400.0f, 40);
		cpSpaceResizeActiveHash(mSpace, 100, 600);
		
		mCharacter = [[Character alloc] initWithCoordinates:cpv(140, 120) inSpace:mSpace];
		[self addChild:mCharacter];

		TriangleCoordinates t;
		t.coordinates = cpv(160, 0);
		t.width = 70;
		
		mTriangle = [[RotatingTriangle alloc] initWithTriangleCoordinates:t angle:OBTUSE inSpace:mSpace];
		[self addChild:mTriangle];
		
		t.coordinates = cpv(140, 80);
		t.width = 70;
		
		mTriangle = [[RotatingTriangle alloc] initWithTriangleCoordinates:t angle:OBTUSE inSpace:mSpace];
		[self addChild:mTriangle];
		
		t.coordinates = cpv(180, 160);
		t.width = 70;
		
		mTriangle = [[RotatingTriangle alloc] initWithTriangleCoordinates:t angle:OBTUSE inSpace:mSpace];
		[self addChild:mTriangle];
		
		t.coordinates = cpv(160, 240);
		t.width = 70;
		
		mTriangle = [[RotatingTriangle alloc] initWithTriangleCoordinates:t angle:OBTUSE inSpace:mSpace];
		[self addChild:mTriangle];
		
		t.coordinates = cpv(140, 320);
		t.width = 70;
		
		mTriangle = [[RotatingTriangle alloc] initWithTriangleCoordinates:t angle:OBTUSE inSpace:mSpace];
		[self addChild:mTriangle];
		
		t.coordinates = cpv(160, 400);
		t.width = 70;
		
		mTriangle = [[RotatingTriangle alloc] initWithTriangleCoordinates:t angle:OBTUSE inSpace:mSpace];
		[self addChild:mTriangle];
		
		t.coordinates = cpv(180, 480);
		t.width = 70;
		
		mTriangle = [[RotatingTriangle alloc] initWithTriangleCoordinates:t angle:OBTUSE inSpace:mSpace];
		[self addChild:mTriangle];
		
		int characterCollision = CHARACTER_COLLISION;
		int triangleCollision = TRIANGLE_COLLISION;
		
		cpSpaceAddCollisionHandler(mSpace, characterCollision, triangleCollision, &characterTriangleBegin, &characterTrianglePreSolve, &characterTrianglePostSolve, &characterTriangleSeparate, self);
		
		[self schedule: @selector(step:)];
}
	return self;
}

-(void) step: (ccTime) delta
{
	
	int steps = 2;
	CGFloat dt = delta/(CGFloat)steps;
	
	
	for(int i=0; i<steps; i++){
		cpSpaceStep(mSpace, dt);
	}
	cpSpaceHashEach(mSpace->activeShapes, &eachShape, self);
	cpSpaceHashEach(mSpace->staticShapes, &eachShape, self);
}

-(void) draw {
	drawSpace(mSpace, &options);
}

#pragma mark -
#pragma mark Accelerometer implementation

-(void) onEnter
{
	[super onEnter];
	
	[[UIAccelerometer sharedAccelerometer] setUpdateInterval:(1.0 / 60)];
}


- (void)accelerometer:(UIAccelerometer*)accelerometer didAccelerate:(UIAcceleration*)acceleration
{	
	static float prevX=0, prevY=0;
	
#define kFilterFactor 0.05f
	
	float accelX = (float) acceleration.x * kFilterFactor + (1- kFilterFactor)*prevX;
	float accelY = (float) acceleration.y * kFilterFactor + (1- kFilterFactor)*prevY;
	
	prevX = accelX;
	prevY = accelY;
	
	mAccel = cpv(accelX, accelY);
}
That's it.

Any help regarding this is deeply appreciated.
Thanks in advance.
Varun Singh
User avatar
slembcke
Site Admin
Posts: 4166
Joined: Tue Aug 14, 2007 7:13 pm
Contact:

Re: cpBody Rotation not consistent

Post by slembcke »

So a couple things to note when reading over your code.
  • High mass ratios like 200:1 are a very bad idea. This is the main part of your problem, and is a problem with pretty much every physics engine ever made.
  • I don't think your pin joint connects where you want it to. Don't you want it to connect at the center (cpvzero) of mBody? This is maybe the second part of your problem.
  • Triangles should only have 3 vertexes not 6. Don't double up the corners.
  • Why do this: mStaticBody->p = cpv(mCentroid.x, mCentroid.y); When you could do this: mStaticBody->p = mCentroid;
  • Why create the body with an infinite moment of inertia, then later overwrite it?
  • PostSolve() and Separate() callbacks do not need to return a value.
  • You don't need to implement collision callbacks that do nothing, just pass NULL for that function pointer.
Can't sleep... Chipmunks will eat me...
Check out our latest projects! -> http://howlingmoonsoftware.com/wordpress/
varunsingh
Posts: 4
Joined: Wed Jul 20, 2011 8:15 am
Contact:

Re: cpBody Rotation not consistent

Post by varunsingh »

slembcke wrote:So a couple things to note when reading over your code.
  • High mass ratios like 200:1 are a very bad idea. This is the main part of your problem, and is a problem with pretty much every physics engine ever made.
    - I changed it to 200:300. Its still giving desirable results which is good.
  • I don't think your pin joint connects where you want it to. Don't you want it to connect at the center (cpvzero) of mBody? This is maybe the second part of your problem.
    - This was where the biggest problem was. I was creating all the bodies at the centre of the space and was giving absolute vector positions to the triangular vertices for shape. I changed the position of the body to mCentreVertex and gave relative positions to the vertices vector for shape.
  • Triangles should only have 3 vertexes not 6. Don't double up the corners.
    - Rectified. I had got that stupid habit from OpenGL drawing.
  • Why do this: mStaticBody->p = cpv(mCentroid.x, mCentroid.y); When you could do this: mStaticBody->p = mCentroid;
    - I was aware of this and have followed the short-hand everywhere else. I was just trying to be more descriptive and readable here.
  • Why create the body with an infinite moment of inertia, then later overwrite it?
    - Haven't changed it yet. Didn't know what value to give initially since the body has to be created before setting its Moment.
  • PostSolve() and Separate() callbacks do not need to return a value.
    - Rectified.
  • You don't need to implement collision callbacks that do nothing, just pass NULL for that function pointer.
    - Rectified.

Thanks. Your reply was actually eye-opening for me. I was skipping some ground rules accidentally.

Thanks once again.

Varun Singh
Post Reply

Who is online

Users browsing this forum: No registered users and 25 guests