Params for Board Game Pieces

Official forum for the Chipmunk2D Physics Library.
Post Reply
E-train
Posts: 2
Joined: Mon Nov 29, 2010 1:28 pm
Contact:

Params for Board Game Pieces

Post by E-train »

Hi, I am building a board game, (WARNIING:Noob here) would like the pieces to push one another out of the way when a game piece is dragged. I browsed the Chipmonk 'Tank' example hoping it would give insight into setting up the correct space, body, constraint params. Got rid of gravity, changed u to .7, e to 0. The pieces don't feel natural and are floating around richochet. Don't think I know what I'm doing yet, any help would be apprecciated. I'm looking to simulate the natural feel of a backgammon piece being dragged and pushing other pieces on the board out of the way.

Some code I'm using:

cpVect mousePoint;
cpVect mousePoint_last;
cpBody *mouseBody = NULL;
cpConstraint *mouseJoint = NULL;

#define GRABABLE_MASK_BIT (1<<31)
#define NOT_GRABABLE_MASK (~GRABABLE_MASK_BIT)


enum {
kTagBatchNode = 1,
};

static void
eachShape(void *ptr, void* unused)
{
cpShape *shape = (cpShape*) ptr;
CCSprite *sprite = shape->data;
if( sprite ) {
cpBody *body = shape->body;

// TIP: cocos2d and chipmunk uses the same struct to store it's position
// chipmunk uses: cpVect, and cocos2d uses CGPoint but in reality the are the same
// since v0.7.1 you can mix them if you want.
[sprite setPosition: body->p];

[sprite setRotation: (float) CC_RADIANS_TO_DEGREES( -body->a )];
}
}

// HelloWorld implementation
@implementation HelloWorld

+(id) scene
{
// 'scene' is an autorelease object.
CCScene *scene = [CCScene node];

// 'layer' is an autorelease object.
HelloWorld *layer = [HelloWorld node];

// add layer as a child to scene
[scene addChild: layer];

// return the scene
return scene;
}


-(void) addNewSpriteX: (float)x y:(float)y
{
int posx, posy;
cpFloat mass = 10.0f;

CCSpriteBatchNode *batch = (CCSpriteBatchNode*) [self getChildByTag:kTagBatchNode];

posx = (CCRANDOM_0_1() * 200);
posy = (CCRANDOM_0_1() * 200);

posx = (posx % 4) * 85;
posy = (posy % 3) * 121;

CCSprite *sprite = [CCSprite spriteWithBatchNode:batch rect:CGRectMake(posx, posy, 85, 121)];
[batch addChild: sprite];

sprite.position = ccp(x,y);

int num = 4;
CGPoint verts[] = {
ccp(-24,-54),
ccp(-24, 54),
ccp( 24, 54),
ccp( 24,-54),
};

cpBody *body = cpBodyNew(mass, cpMomentForPoly(mass, num, verts, CGPointZero));
// cpBody *body = cpBodyNew(1.0f, cpMomentForPoly(1.0f, num, verts, CGPointZero));

// TIP:
// since v0.7.1 you can assign CGPoint to chipmunk instead of cpVect.
// cpVect == CGPoint
body->p = ccp(x, y);
cpSpaceAddBody(space, body);

cpShape* shape = cpPolyShapeNew(body, num, verts, CGPointZero);
// shape->e = 0.5f; shape->u = 0.5f;
shape->e = 0.0f; shape->u = .7f;
shape->data = sprite;
cpSpaceAddShape(space, shape);

}
-(id) init
{
if( (self=[super init])) {

self.isTouchEnabled = YES;
self.isAccelerometerEnabled = YES;

CGSize wins = [[CCDirector sharedDirector] winSize];
cpInitChipmunk();

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;
space->damping = 0.95f;

cpShape *shape;

// bottom
shape = cpSegmentShapeNew(staticBody, ccp(0,0), ccp(wins.width,0), 0.0f);
shape->e = 1.0f; shape->u = 1.0f;
cpSpaceAddStaticShape(space, shape);

// top
shape = cpSegmentShapeNew(staticBody, ccp(0,wins.height), ccp(wins.width,wins.height), 0.0f);
shape->e = 1.0f; shape->u = 1.0f;
cpSpaceAddStaticShape(space, shape);

// left
shape = cpSegmentShapeNew(staticBody, ccp(0,0), ccp(0,wins.height), 0.0f);
shape->e = 1.0f; shape->u = 1.0f;
cpSpaceAddStaticShape(space, shape);

// right
shape = cpSegmentShapeNew(staticBody, ccp(wins.width,0), ccp(wins.width,wins.height), 0.0f);
shape->e = 1.0f; shape->u = 1.0f;
cpSpaceAddStaticShape(space, shape);

CCSpriteBatchNode *batch = [CCSpriteBatchNode batchNodeWithFile:@"grossini_dance_atlas.png" capacity:100];
[self addChild:batch z:0 tag:kTagBatchNode];

[self addNewSpriteX: 100 y:50];
[self addNewSpriteX: 100 y:100];
[self addNewSpriteX: 100 y:150];
[self addNewSpriteX: 100 y:200];
[self addNewSpriteX: 150 y:200];
[self addNewSpriteX: 200 y:200];
[self addNewSpriteX: 250 y:200];
[self addNewSpriteX: 300 y:200];
[self addNewSpriteX: 350 y:250];
[self addNewSpriteX: 350 y:200];
[self addNewSpriteX: 350 y:150];
[self addNewSpriteX: 350 y:100];
[self addNewSpriteX: 350 y:50];


mousePoint = cpv(0, 0);
mouseBody = cpBodyNew(INFINITY, INFINITY);


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

return self;
}

-(void) onEnter
{
[super onEnter];

[[UIAccelerometer sharedAccelerometer] setUpdateInterval:(1.0 / 60)];
}

-(void) step: (ccTime) delta
{
cpVect newPoint = cpvlerp(mousePoint_last, mousePoint, 0.25f);
mouseBody->p = newPoint;
mouseBody->v = cpvmult(cpvsub(newPoint, mousePoint_last), 60.0f);

mousePoint_last = newPoint;


int steps = 2;
CGFloat dt = delta/(CGFloat)steps;

for(int i=0; i<steps; i++){
cpSpaceStep(space, dt);
}
cpSpaceHashEach(space->activeShapes, &eachShape, nil);
cpSpaceHashEach(space->staticShapes, &eachShape, nil);

}

- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(@"in CCTouchesBegan");


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);
}

// return YES;
}

- (void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(@"in CCTouchesMove");

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
{
NSLog(@"in CCTouchesEnded");

/*
for( UITouch *touch in touches ) {
CGPoint location = [touch locationInView: [touch view]];

location = [[CCDirector sharedDirector] convertToGL: location];

[self addNewSpriteX: location.x y:location.y];
}
*/

if (cpArrayContains(space->constraints, mouseJoint)) {
cpSpaceRemoveConstraint(space, mouseJoint);
cpConstraintFree(mouseJoint);
mouseJoint = nil;
}
}
User avatar
slembcke
Site Admin
Posts: 4166
Joined: Tue Aug 14, 2007 7:13 pm
Contact:

Re: Params for Board Game Pieces

Post by slembcke »

The key part of the Tank demo is that it uses constraints configured in a non-conventional way to calculate the friction correctly. In a top down game, Chipmunk has no sense of friction between the ground objects. Fortunately it is possible to fake top-down friction quite effectively.

Each of the boxes in the Tank demo has two joints attached to it:

Code: Select all

cpConstraint *pivot = cpSpaceAddConstraint(space, cpPivotJointNew2(staticBody, body, cpvzero, cpvzero));
pivot->biasCoef = 0.0f; // disable joint correction
pivot->maxForce = 1000.0f; // emulate linear friction

cpConstraint *gear = cpSpaceAddConstraint(space, cpGearJointNew(staticBody, body, 0.0f, 1.0f));
gear->biasCoef = 0.0f; // disable joint correction
gear->maxForce = 5000.0f; // emulate angular friction
By setting biasCoef to 0, the joints won't correct themselves when they get out of shape. This means that only the velocity will be modified, and the force is clamped to a maximum value. This is exactly how friction would be calculated. All you have to do is guess reasonable force values for the linear and angular friction.

You might also want to look at the Objective-Chipmunk example iPhone game "Snap" that is included with Chipmunk. It's also a top down board game and it uses the ChipmunkObject protocol to make managing all the joints and such easier.
Can't sleep... Chipmunks will eat me...
Check out our latest projects! -> http://howlingmoonsoftware.com/wordpress/
E-train
Posts: 2
Joined: Mon Nov 29, 2010 1:28 pm
Contact:

Re: Params for Board Game Pieces

Post by E-train »

Thanks. Slembke. Worked great.
Post Reply

Who is online

Users browsing this forum: No registered users and 18 guests