Manually Moving the Body

Official forum for the Chipmunk2D Physics Library.
Post Reply
Xcode
Posts: 8
Joined: Sat Apr 24, 2010 9:30 am
Contact:

Manually Moving the Body

Post by Xcode »

Well do i need to rewrite cpBodyUpdatePosition if i have to move the body manually?
I have a ball falling off(bcoz of gravity) , if user touches the ball during flight and drags, its position should change.. One way was to just changing the body's position,,,,but i read in some post that changing just the position is like teleporting the body(it keeps its original velocity and other paramters) . So whats the correct way of doing it in Chipmunk...

Thanks for your help :)
User avatar
slembcke
Site Admin
Posts: 4166
Joined: Tue Aug 14, 2007 7:13 pm
Contact:

Re: Manually Moving the Body

Post by slembcke »

You will rarely need to change the position update function. The easiest thing to do is just to change the velocity update function to call cpBodySlew() to set the velocity so that it will move to the desired place.

Probably a better solution of you want nice dragging behavior is to implement the mouse grabbing controls using a soft joint like the demos do. It's pretty simple:

Code: Select all

static void
click(int button, int state, int x, int y)
{
	if(button == GLUT_LEFT_BUTTON){
		if(state == GLUT_DOWN){
			cpVect point = mouseToSpace(x, y);
		
			cpShape *shape = cpSpacePointQueryFirst(space, point, GRABABLE_MASK_BIT, 0);
			if(shape){
				cpBody *body = shape->body;
				mouseJoint = cpPivotJointNew2(mouseBody, body, cpvzero, cpBodyWorld2Local(body, point));
				mouseJoint->maxForce = 50000.0f;
				mouseJoint->biasCoef = 0.15f;
				cpSpaceAddConstraint(space, mouseJoint);
			}
		} else if(mouseJoint){
			cpSpaceRemoveConstraint(space, mouseJoint);
			cpConstraintFree(mouseJoint);
			mouseJoint = NULL;
		}
	}
}
This enables and disables the joint.

Code: Select all

	cpVect newPoint = cpvlerp(mousePoint_last, mousePoint, 0.25f);
	mouseBody->p = newPoint;
	mouseBody->v = cpvmult(cpvsub(newPoint, mousePoint_last), 60.0f);
	mousePoint_last = newPoint;
This updates the position and velocity of the cpBody attached to the mouse cursor.
Can't sleep... Chipmunks will eat me...
Check out our latest projects! -> http://howlingmoonsoftware.com/wordpress/
Xcode
Posts: 8
Joined: Sat Apr 24, 2010 9:30 am
Contact:

Re: Manually Moving the Body

Post by Xcode »

Hey Thanks, that really worked :)
byers
Posts: 2
Joined: Wed May 05, 2010 9:25 am
Contact:

Re: Manually Moving the Body

Post by byers »

hey there,

this topic is somewhat related, but if it should be in it's own post, apologies...

i'm working on a cocos2d game which has a bunch of objects that need to be dragged around.

using the technique from the tank example, i'm trying to port the mousejoint constraint logic to have my object body properly respond to the touchBegan and touchMoved events.

i'm fairly new to cocos2d and i'm not quite sure about how to "connect" the new movements of the joints/mousebody and how to update the position of the sprite that is set to the shape's data property.

below is a snippet from what i've done so far. i'm at a loss to determine where is the recommended place to update the sprite object's position/orientation? or am i going down the wrong path completely?!?!??!

Code: Select all


-(id) init {
	if( (self=[super init])) {
		
		self.isTouchEnabled = YES;
		
		CGSize wins = [[CCDirector sharedDirector] winSize];
		cpInitChipmunk();
		
		mouseBody = cpBodyNew(INFINITY, INFINITY);
		
		cpBody *staticBody = cpBodyNew(INFINITY, INFINITY);
		space = cpSpaceNew();
		cpSpaceResizeStaticHash(space, 400.0f, 40);
		cpSpaceResizeActiveHash(space, 100, 600);
		
		space->gravity = ccp(0, 0);
		space->elasticIterations = space->iterations;

		[self schedule: @selector(step:)];
}

-(void) step {

	int steps = 1;
	cpFloat dt = 1.0f/60.0f/(cpFloat)steps;

	for(int i=0; i<steps; i++){
		// turn the control body based on the angle relative to the actual body
		cpVect mouseDelta = cpvsub(mousePoint, spaceBody->p);
		
		cpFloat turn = cpvtoangle(cpvunrotate(spaceBody->rot, mouseDelta));
		
		cpBodySetAngle(spaceControlBody, spaceBody->a - turn);
		
		// drive the tank towards the mouse
		if(cpvnear(mousePoint, spaceBody->p, 30.0)){
			spaceControlBody->v = cpvzero; // stop
		} else {
			cpFloat direction = (cpvdot(mouseDelta, spaceBody->rot) > 0.0 ? 1.0 : -1.0);
			spaceControlBody->v = cpvrotate(spaceBody->rot, cpv(30.0f*direction, 0.0f));
		}
		cpSpaceStep(space, dt);
	}

}

-(void) makeSpaceShips {
	
	CGSize winSize = [[CCDirector sharedDirector] winSize];

	CCTexture2D * texture = [[CCTextureCache sharedTextureCache] addImage:@"space.png"];
	spaceOne = [[CCSprite alloc] initWithTexture:texture];
	spaceOne.rotation = -90.f;
	spaceOne.position = CGPointMake(winSize.width/2 - (spaceOne.contentSize.width/2) + 20, 100);
	[self addChild:spaceOne z:10];

	// 86 x 47
	cpVect oneVerts[] = {
	cpv(43, 23.5),
	cpv(43, -23.5),
	cpv(-43, -23.5), 
	cpv(-43, 23.5), 
	};
	
	spaceBody = cpBodyNew(100.0, INFINITY);
	spaceBody->p = cpv(winSize.width/2 - (spaceOne.contentSize.width/2) + 20, 100);
	cpSpaceAddBody(space, spaceBody);
	
	cpShape * spaceOneShape = cpPolyShapeNew(spaceBody, 4, oneVerts, cpvzero);
	spaceOneShape->data = spaceOne;
	spaceOneShape->e = 0.0;
	spaceOneShape->u = 0.0;
	spaceOneShape->collision_type = 1;
	cpSpaceAddShape(space, spaceOneShape);
	
	spaceControlBody = cpBodyNew(INFINITY, INFINITY);
	
	cpConstraint * pivot = cpSpaceAddConstraint(space, cpPivotJointNew2(spaceControlBody, spaceBody, cpvzero, cpvzero));
	pivot->biasCoef = 0.0f; // disable joint correction
	pivot->maxForce = 10000.0f; // emulate linear friction

	cpConstraint * gear = cpSpaceAddConstraint(space, cpGearJointNew(spaceControlBody, spaceBody, 0.0f, 1.0f));
	gear->biasCoef = 1.0f; // limit angular correlation rate
	gear->maxBias = 1.0f; // limit angular correction rate
	gear->maxForce = 500000.f; // emulate angular friction
	
}

-(void) ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
	
	UITouch *myTouch = [touches anyObject];
	
	CGPoint location = [myTouch locationInView: [myTouch view]];
	location = [[CCDirector sharedDirector] convertToGL: location];
	
	cpVect point =  [self convertTouchToNodeSpace:myTouch]; //cpv(location.x, location.y);
	mousePoint = point;
	
	cpShape *shape = cpSpacePointQueryFirst(space, location, GRABABLE_MASK_BIT, 0);
	if ( shape ) {
		cpBody *body = shape->body;
		
		mousePoint_last = mousePoint;
		mouseBody->p = mousePoint;
		
		mouseJoint = cpPivotJointNew2(mouseBody, body, cpvzero, cpBodyWorld2Local(body, location));
		mouseJoint->maxForce = 50000.0f;
		mouseJoint->biasCoef = 0.15f;
		cpSpaceAddConstraint(space, mouseJoint);
	}
	
}

-(void) ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
	
	UITouch *myTouch = [touches anyObject];
	
	CGPoint location = [myTouch locationInView: [myTouch view]];
	location = [[CCDirector sharedDirector] convertToGL: location];
	
	cpVect point = [self convertTouchToNodeSpace:myTouch]; // cpv(location.x, location.y);
	mousePoint = point;
	
}

-(void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {

	if (cpArrayContains(space->constraints, mouseJoint)) {
		cpSpaceRemoveConstraint(space, mouseJoint);
		cpConstraintFree(mouseJoint);
		mouseJoint = nil;
	}
	
}

byers
Posts: 2
Joined: Wed May 05, 2010 9:25 am
Contact:

Re: Manually Moving the Body

Post by byers »

ok, figured out the problem. from the tick/display method i needed to first properly set the latest mouse position, then iterate through my set of active sprites and update their position / rotation.
barabashka
Posts: 1
Joined: Mon Nov 08, 2010 8:34 am
Contact:

Re: Manually Moving the Body

Post by barabashka »

Hi! Here's a way i'm doing that.

Code: Select all

cpVect mousePosLast;
cpBody *dragBody = 0;

void clickFunc(int button, int state, int x, int y)
{
	if( button == GLUT_LEFT_BUTTON )
	{
		if( state == GLUT_DOWN )
		{
			mousePosLast = mouseToSpace(x, y);

			cpShape *shape = cpSpacePointQueryFirst(space, mousePosLast, CP_ALL_LAYERS, CP_NO_GROUP);

			dragBody = (shape) ? shape->body : 0;
		}
		else
			dragBody = 0;
	}
}

void dragFunc(int x, int y)
{
	if( dragBody )
	{
		cpVect mousePos = mouseToSpace(x, y);

		// Update body's position
		dragBody->p = cpvadd(dragBody->p, cpvsub(mousePos, mousePosLast));
		// Stop body. Isn't necessary
		dragBody->v = cpvzero;
		
		// Walk throught body's shapes and update space hash for them
		cpShape *shapes = dragBody->shapesList;

		while( shapes )
		{
			cpSpaceRehashShape(space, shapes);
			shapes = shapes->next;
		}

		mousePosLast = mousePos;

		glutPostRedisplay();
	}
}

Post Reply

Who is online

Users browsing this forum: No registered users and 13 guests