Cocos2dx, box2d tank - c++

I'm trying to make a tank in cocos2d-x with box2d. Everything works fine but when i draw the tank, the barrel is in the middle as you can see in the picture.
To draw the tank i set the position to the center of the screen, after the tank body is drawn i want to draw the barrel and i give it the center of the screen + the same offset of the joint (the joint is on the right position).
Both anchor points, the tank and barrel are on (0.5, 0.5) and because i use the same offset as the joint i expected the barrel was drawn at the right place but it's not.
My code:
// Create sprite and add it to the layer
CCSprite *tank = CCSprite::create();
//tank->initWithFile("Tanks/001/tank.png");
tank->setPosition(pos);
tank->setTag(1);
this->addChild(tank);
// Create ball body
b2BodyDef tankBodyDef;
tankBodyDef.type = b2_dynamicBody;
tankBodyDef.position = toMeters(&pos);
tankBodyDef.userData = tank;
b2Body *tankBody = _world->CreateBody(&tankBodyDef);
// Create shape definition and add body
shapeCache->addFixturesToBody(tankBody, "001/tank");
// Create sprite and add it to the layer
CCSprite *barrel = CCSprite::create();
//barrel->initWithFile("Tanks/001/barrel.png");
barrel->setPosition(CCPointMake(pos.x + 77, pos.y+117));
barrel->setTag(2);
this->addChild(barrel);
// Create barrel body
barrelBodyDef.type = b2_dynamicBody;
barrelBodyDef.userData = barrel;
barrelBodyDef.position = b2Vec2(tankBodyDef.position.x + 2.40625, tankBodyDef.position.y + 3.65625); // = same offset as joint!?!?!
b2Body *barrelBody = _world->CreateBody(&barrelBodyDef);
// Create shape definition and add body
shapeCache->addFixturesToBody(barrelBody, "001/barrel");
// Create a joint
//
b2RevoluteJointDef armJointDef;
//armJointDef.Initialize(tankBody, barrelBody, b2Vec2(400.0f/PTM_RATIO, 450/PTM_RATIO));
armJointDef.bodyA = tankBody;
armJointDef.bodyB = barrelBody;
armJointDef.localAnchorA.Set(2.40625, 3.65625);
armJointDef.localAnchorB.Set(-2.90625, -0.125);
armJointDef.enableMotor = true;
armJointDef.enableLimit = true;
armJointDef.motorSpeed = 10;
armJointDef.referenceAngle = CC_DEGREES_TO_RADIANS(0); // begin graden
armJointDef.lowerAngle = CC_DEGREES_TO_RADIANS(-50); // max graden naar beneden
armJointDef.upperAngle = CC_DEGREES_TO_RADIANS(00); // max graden naar boven
armJointDef.maxMotorTorque = 48;
armJoint = (b2RevoluteJoint*)_world->CreateJoint(&armJointDef);
I hope somebody got an answer :)

Problem solved :), i had to add the offset of the barrel anchor too, now it's on the right position.

Related

How to create a tank with cocos2dx

Me and a friend of mine are trying to make a tank with cocos2dx.
we are so far that the tank is on the screen and the barrel is attached to the tank
but now we want to try to the rotate the barrel but nothing is happening, the joint is at the center where the barrel start en de dome ends. both the tank and the barrel are dynamic bodies and we are using a friction joint (see code)
// Create sprite and add it to the layer
CCSprite *tank = CCSprite::create();
//tank->initWithFile("../Resources/tanks/001/tank.png");
tank->setPosition(pos);
tank->setTag(1);
this->addChild(tank);
// Create ball body
b2BodyDef tankBodyDef;
tankBodyDef.type = b2_dynamicBody;
tankBodyDef.position = toMeters(&pos);
tankBodyDef.userData = tank;
tankBody = _world->CreateBody(&tankBodyDef);
// Create shape definition and add body
shapeCache->addFixturesToBody(tankBody, "001/tank");
pos = CCPointMake(580, 450);
// Create sprite and add it to the layer
CCSprite *barrel = CCSprite::create();
//barrel->initWithFile("Tanks/001/barrel.png");
barrel->setPosition(pos);
barrel->setTag(2);
this->addChild(barrel);
// Create ball body
b2BodyDef barrelBodyDef;
barrelBodyDef.type = b2_dynamicBody;
barrelBodyDef.position = toMeters(&pos);
barrelBodyDef.userData = barrel;
barrelBody = _world->CreateBody(&barrelBodyDef);
tankBarrelAnchor = CreateRevoluteJoint(tankBody, barrelBody, -85.f, 180.f, 2000000.f, 0.f, true, false);
tankBarrelAnchor->localAnchorA = b2Vec2(0, 0);
tankBarrelAnchor->localAnchorB = b2Vec2(0, 0);
tankBarrelAnchor->referenceAngle = 0;
joint = (b2RevoluteJoint*)_world->CreateJoint(tankBarrelAnchor);
b2RevoluteJointDef* Level::CreateRevoluteJoint(b2Body* A, b2Body* B, float lowerAngle, float upperAngle, float maxMotorTorque, float motorSpeed, boolean enableMotor, boolean collideConnect){
b2RevoluteJointDef *revoluteJointDef = new b2RevoluteJointDef();
revoluteJointDef->bodyA = A;
revoluteJointDef->bodyB = B;
revoluteJointDef->collideConnected = collideConnect;
revoluteJointDef->lowerAngle = CC_DEGREES_TO_RADIANS(lowerAngle);
revoluteJointDef->upperAngle = CC_DEGREES_TO_RADIANS(upperAngle);
revoluteJointDef->enableLimit = true;
revoluteJointDef->enableMotor = enableMotor;
revoluteJointDef->maxMotorTorque = maxMotorTorque;
revoluteJointDef->motorSpeed = CC_DEGREES_TO_RADIANS(motorSpeed); //1 turn per second counter-clockwise
return revoluteJointDef;
}
I think the problem is that your anchor positions are not correct. This setting:
tankBarrelAnchor->localAnchorA = b2Vec2(0, 0);
tankBarrelAnchor->localAnchorB = b2Vec2(0, 0);
... would put the anchors at those two red and green axes you can see in your screenshot, and it will try to pull those two points together. Try turning on the joints display in the debug draw and this should be more obvious.
You need to give the anchors as local coordinates from the point of view of each body. For example from the point of view of the tank body, the swivel point looks like (1,2) and from the point of view of the barrel body, it looks like (-1,0). Of course the dimensions you are using are probably different, but the directions should be somewhat similar.
See the "Local anchors" section here: http://www.iforce2d.net/b2dtut/joints-revolute

how to prevent softbody ball from destruction in box2d?

I have used soft body physics in my game to make ball.Now when ball falls down on some platforms which are also b2Bodies or on GrounBody it completely destroyed & it's shape also changed.
I have referred this link : http://www.uchidacoonga.com/2012/04/soft-body-physics-with-box2d-and-cocos2d-part-44/
but when i am trying to change some of values like radius,frequencyHz ,dampingRatio etc then it gives result as per my first image , in which my ball looks so unshaped & destructed .
- (void) createPhysicsObject:(b2World *)world {
// Center is the position of the circle that is in the center (inner circle)
b2Vec2 center = b2Vec2(240/PTM_RATIO, 160/PTM_RATIO);
b2CircleShape circleShape;
circleShape.m_radius = 0.20f;
b2FixtureDef fixtureDef;
fixtureDef.shape = &circleShape;
fixtureDef.density = 0.1;
fixtureDef.restitution = -2;
fixtureDef.friction = 1.0;
// Delta angle to step by
deltaAngle = (2.f * M_PI) / NUM_SEGMENTS;
// Radius of the wheel
float radius = 50;
// Need to store the bodies so that we can refer back
// to it when we connect the joints
bodies = [[NSMutableArray alloc] init];
for (int i = 0; i < NUM_SEGMENTS; i++) {
// Current angle
float theta = deltaAngle*i;
// Calculate x and y based on theta
float x = radius*cosf(theta);
float y = radius*sinf(theta);
// Remember to divide by PTM_RATIO to convert to Box2d coordinate
b2Vec2 circlePosition = b2Vec2(x/PTM_RATIO, y/PTM_RATIO);
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
// Position should be relative to the center
bodyDef.position = (center + circlePosition);
// Create the body and fixture
b2Body *body;
body = world->CreateBody(&bodyDef);
body->CreateFixture(&fixtureDef);
// Add the body to the array to connect joints to it
// later. b2Body is a C++ object, so must wrap it
// in NSValue when inserting into it NSMutableArray
[bodies addObject:[NSValue valueWithPointer:body]];
}
// Circle at the center (inner circle)
b2BodyDef innerCircleBodyDef;
// Make the inner circle larger
circleShape.m_radius = 0.8f;
innerCircleBodyDef.type = b2_dynamicBody;
// Position is at the center
innerCircleBodyDef.position = center;
innerCircleBody = world->CreateBody(&innerCircleBodyDef);
innerCircleBody->CreateFixture(&fixtureDef);
// Connect the joints
b2DistanceJointDef jointDef;
for (int i = 0; i < NUM_SEGMENTS; i++) {
// The neighbor
const int neighborIndex = (i + 1) % NUM_SEGMENTS;
// Get current body and neighbor
b2Body *currentBody = (b2Body*)[[bodies objectAtIndex:i] pointerValue];
b2Body *neighborBody = (b2Body*)[[bodies objectAtIndex:neighborIndex] pointerValue];
// Connect the outer circles to each other
jointDef.Initialize(currentBody, neighborBody,
currentBody->GetWorldCenter(),
neighborBody->GetWorldCenter() );
// Specifies whether the two connected bodies should collide with each other
jointDef.collideConnected = true;
jointDef.frequencyHz = 25.0f;
jointDef.dampingRatio = 0.5f;
world->CreateJoint(&jointDef);
// Connect the center circle with other circles
jointDef.Initialize(currentBody, innerCircleBody, currentBody->GetWorldCenter(), center);
jointDef.collideConnected = true;
jointDef.frequencyHz = 25.0;
jointDef.dampingRatio = 0.5;
world->CreateJoint(&jointDef);
}
}
This code give me the result as shown here.Is there any solution to avoid this situation ???
i want output like this
for that what changes i should made ? any suggestions !! please help.
i would also like to know the reason behind this.
It looks like the triangle fan is reacting with itself. Since you use a triangle fan to create a ball the triangles shouldn't interact, they are connected only. The code on the website you provided is a little bit different. After the first jointDef.Initialize the frequency and dampingRatio are 0.
But some other informations are missing like your NUM_SEGMENTS. Provide complete working code/functions (not the whole application), so someone other could compile and check it also.

Rotating CCSprite thats an equilateral triangle

I have an CCSprite thats an equilateral triangle. I want to rotate the triangle in 60 degree increments holding its position.
The sprite is 126x110 (not square) setting the sprites rotation property in 60 degree increments changes the position of the sprite. How can i keep the sprite appear stationary at each rotation?
A bit more about this the center of the rectangle IS NOT the center of the sprite. So there is some adjustment needed when the rotation is needed to keep the center of the triangle appearing centered.
I think i came up with a long answer that needs to be approved..
// collect points.
self.point1 = CGPointMake(CGRectGetWidth(self.tile.boundingBox)/2, 0);
self.point2 = CGPointMake(CGRectGetWidth(self.tile.boundingBox), CGRectGetHeight(self.tile.boundingBox));
self.point3 = CGPointMake(0, CGRectGetHeight(self.tile.boundingBox));
// calculcate the mid point.
float midPointX = floor((self.point1.x + self.point2.x + self.point3.x)/3.0);
float midPointY = floor((self.point1.y + self.point2.y + self.point3.y)/3.0);
// stash the center of the triangle
self.triangleCenter = CGPointMake(midPointX, midPointY);
Then figure out new location of the center point based on rotation.. And animate there. (Sorry about hard coded center of the screen this was a rough test).
-(void) rotateToAngleAboutCenter:(float)angle {
// stash old values.
CGPoint oldPosition = self.tile.position;
float oldRotation = self.tile.rotation;
// reset the rotation
self.tile.rotation = 0;
// this is hard coded here currently the center of the screen.
self.tile.position = ccp(512, 384);
// figure out where our center point will be when we are rotated about the center.
CGPoint point = ccpRotateByAngle(self.triangleCenter, [self.tile anchorPointInPoints],-CC_DEGREES_TO_RADIANS(angle));
// convert the ppoint to local space.
point = [self.tile convertToWorldSpace:point];
point = [self convertToNodeSpace:point];
// reset the rotation and position.
self.tile.rotation = oldRotation;
self.tile.position = oldPosition;
// animate to new rotation/position.
CCMoveTo* moveTo = [CCMoveTo actionWithDuration:.25 position:point];
CCRotateTo* rotateTo = [CCRotateTo actionWithDuration:.25 angle:angle];
[self.tile runAction:moveTo];
[self.tile runAction:rotateTo];
}

How to rotate the physics or dynamic body along an arc path in cocos2d(box2D)

As I am newbie to cocoa2d I am struggling alot to rotate the physics or dynamic body along an arc path.
The way I tried is as follows:
#define COS_ANIMATOR(position, timeCount, speed, waveMagnitude) ((cosf(timeCount * speed) * waveMagnitude) + position)
#define SIN_ANIMATOR(position, timeCount, speed, waveMagnitude) ((sinf(timeCount * speed) * waveMagnitude) + position)
CCSpriteBatchNode *pipe_parent = [CCSpriteBatchNode batchNodeWithFile:#"pipe.png" capacity:100];
CCTexture2D *pipeSpriteTexture_ = [pipe_parent texture];
PhysicsSprite *pipeSprite = [PhysicsSprite spriteWithTexture:pipeSpriteTexture_ rect:CGRectMake(0 ,0 ,55,122)];
//pipe = [CCSprite spriteWithFile:#"pipe.png"
// rect:CGRectMake(0, 0, 55, 122)];
[self addChild:pipeSprite];
// pipe.position = ccp(s.width/2 , 420.0);
b2BodyDef myBodyDef;
myBodyDef.type = b2_staticBody; //this will be a dynamic body
myBodyDef.position.Set(((s.width/2) - 90)/PTM_RATIO, 420.0/PTM_RATIO); //set the starting position
myBodyDef.angle = 0; //set the starting angle
b2Body* staticBody = world->CreateBody(&myBodyDef);
b2PolygonShape boxShape;
boxShape.SetAsBox(1,1);
b2FixtureDef boxFixtureDef;
boxFixtureDef.shape = &boxShape;
boxFixtureDef.density = 1;
boxFixtureDef.userData = pipeSprite;
boxFixtureDef.filter.groupIndex = -1;
staticBody->CreateFixture(&boxFixtureDef);
[pipeSprite setPhysicsBody:staticBody];
-(void) draw
{
//
// IMPORTANT:
// This is only for debug purposes
// It is recommend to disable it
//
[super draw];
const CGPoint newSpritePosition = ccp(COS_ANIMATOR(150, mTimeCounter, 0.05,50), SIN_ANIMATOR(400, mTimeCounter, -0.05, 50));
pipeSprite.position = newSpritePosition;
ccGLEnableVertexAttribs( kCCVertexAttribFlag_Position );
kmGLPushMatrix();
world->DrawDebugData();
kmGLPopMatrix();
}
on following this approach my sprite rotating in circular motion instead of rotating in an arc path.
Please give your ideas or suggestions.
Thanks all
I'm not entirely sure what it is you are looking to accomplish when you talk about rotating in an arc path. I only see you setting a position, not a rotation, so are you just wanting to set a position, or a rotation, or both? Your position code looks like you are trying to achieve a circular (or elliptical) path because you are using the sine and cosine in the x,y position.
If you're looking to move a sprite along a sine curve, I did that today and it took a bit of trial and error. I had some variables for the amplitude and period, and from there I traced out a nice sine curve movement in the sprite's update: method.
CGPoint initialPosition; // set this to the sprite's initial position
float amplitude; // in points
float period; // in points
float y, x = initialPosition.x;
-(void) update:(ccTime)dt
{
x += dt * 100; // speed of movement across the screen. Picked by trial and error.
y = initalPosition.y + amplitude * sinf((x - initialPosition.x)/period);
sprite.position = ccp(x,y);
sprite.rotation = cosf((x - initialPosition.x)/period); // optional if you want to rotate along the path as well
}
Don't know if this is anything you are looking for but it might give you some ideas.

Cocos2d Box2d Scaling Radius Circle Bodies

Currently, in cocos2d, I have a an app that does the following:
Initiate with a Blank Screen.
When I tap the screen, I get a circle to pop-up. As I hold the circle, the circle will continue to grow at a constant rate. However, despite the fact that the sprite is growing, the box2d physical body isn't, which means that the sprite will not collide with other bodies. I been trying to figure out a way to change the radius that scales with the sprite but no such question exist here for cocos2d. I have noticed other box2d for things other than cocos2d but I am having a hard time translating them over.
//smile.position = ccp(touchLocation.x, touchLocation.y);
smile.scale = .05;
[self addChild:smile];
// b2BodyDef smileBodyDef;
smileBodyDef.type = b2_dynamicBody;
smileBodyDef.position.Set(touchLocation.x/PTM_RATIO, touchLocation.y/PTM_RATIO);
smileBodyDef.userData = smile;
smileBody = world->CreateBody(&smileBodyDef);
//Radius
b2CircleShape smileCircleShape;
int radius = 80;
//Fixture
smileFixtureDef.shape = &smileCircleShape;
smileFixtureDef.density = 0.00f;
smileFixtureDef.friction = .2f;
smileBody->CreateFixture(&smileFixtureDef);
if (CGRectContainsPoint(smileRect, touchLocation)) {
growForever = [CCRepeatForever actionWithAction: [CCScaleBy actionWithDuration: .5 scale: 1.2]];
[growForever setTag:1];
[smile runAction:growForever];
Each time you want to change your radius, grab the shape object associated with the b2Fixture that you created for your body, and then set the new value accordingly:
fixture->GetShape()->m_radius = new_radius/PTM_RATIO;