How to create a tank with cocos2dx - c++

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

Related

Body object Throw in a straightline in Box2d

I need to throw my box2d object till off screen.
For example... Rabbit is moving straight on Jungle Path (Road length around 500 metres). In between it got some power to apply, like Axe. So rabbit need to throw that object forward till the off screen. If any bouncable object (like wall and tree) in midway, thrown object need to come back, else it should go to off screen and hide.
At touch event I called below method to create body and for movement I used setlinear velocity.. but it's not moving straight and smooth; then inbetween if any objects (like wall and tree). How to bounce back (reverse travel)?
[self createbody];
-(void) createbody
{
freeBodySprite = [CCSprite spriteWithFile:#"blocks.png"];//web_ani_6_1
//freeBodySprite.position = ccp(100, 300);
[self addChild:freeBodySprite z:2 tag:6];
CGPoint startPos = CGPointMake(100, 320/1.25);
b2BodyDef bodyDef;
bodyDef.type = b2_staticBody;
bodyDef.position = [self toMeters:startPos];
bodyDef.userData = freeBodySprite;
b2CircleShape shape;
float radiusInMeters = ((freeBodySprite.contentSize.width * freeBodySprite.scale/PTM_RATIO) * 0.5f);
shape.m_radius = radiusInMeters;
b2FixtureDef fixtureDef;
fixtureDef.shape = &shape;
fixtureDef.density = 0.07f;
fixtureDef.friction = 0.1f;
fixtureDef.restitution = 0.1f;
b2Fixture *stoneFixture;
circularObstacleBody = world->CreateBody(&bodyDef);
stoneFixture = circularObstacleBody->CreateFixture(&fixtureDef);
freeBody = circularObstacleBody;
}
-(b2Vec2) toMeters:(CGPoint)point
{
return b2Vec2(point.x / PTM_RATIO, point.y / PTM_RATIO);
}
I am bit confused. How to achieve the above requirement ?
I refer this link:- Box2d object throwing smoother and on same velocity
First, In your Code, u didnt show your movement code(where u used that Linear Velocity)
b2vec2 *move = (30,0);
cart->SetLinearVelocity(move);
above code will move your box2d body with 30 velocity in x axis. when ever any object occurs in middle of road. u need to handle those in below methods
void LevelContactListener::BeginContact(b2Contact* contact)
void LevelContactListener::EndContact(b2Contact* contact)
u will get Fixtures from above method. based on that handle the collisons.(i.e.,) your box2d body(player power) and those road objects collided. set the power to reverse direction (-velocity).
You can set friction to 0 and body will nicely bouncing from walls.
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
bodyDef.position.Set(100/PTM_RATIO, 100/PTM_RATIO);
b2Body * body = _world->CreateBody(&bodyDef);
b2CircleShape circle;
circle.m_radius = 26.0/PTM_RATIO;
b2FixtureDef ShapeDef;
ShapeDef.shape = &circle;
ShapeDef.density = 1.0f;
ShapeDef.friction = 0.f;
ShapeDef.restitution = 1.0f;
b2Fixture *bodyFixture = body->CreateFixture(&ShapeDef);
To create walls you need create ground body for example:
b2BodyDef groundBodyDef;
groundBodyDef.position.Set(0,0);
_groundBody = _world->CreateBody(&groundBodyDef);
b2EdgeShape groundBox;
b2FixtureDef groundBoxDef;
groundBoxDef.shape = &groundBox;
groundBox.Set(b2Vec2(0,0), b2Vec2(winSize.width/PTM_RATIO, 0));
_bottomFixture = _groundBody->CreateFixture(&groundBoxDef);
groundBox.Set(b2Vec2(0,0), b2Vec2(0, winSize.height/PTM_RATIO));
_groundBody->CreateFixture(&groundBoxDef);
groundBox.Set(b2Vec2(0, winSize.height/PTM_RATIO), b2Vec2(winSize.width/PTM_RATIO,
winSize.height/PTM_RATIO));
_groundBody->CreateFixture(&groundBoxDef);
groundBox.Set(b2Vec2(winSize.width/PTM_RATIO, winSize.height/PTM_RATIO),
b2Vec2(winSize.width/PTM_RATIO, 0));
_groundBody->CreateFixture(&groundBoxDef);
You may add distance joint that will pull object back to the initial position upon its first contact with other collider (see contact listener for details).
I think it is possible to have persistent joint connected your player with throwable object. You just have to handle joint limits (distance) and behaviour (spring and damper).

How to add sprite in box2d body (c++, cocos2d)?

setTouchEnabled(true);
ball=CCSprite::create("soccer_ball.png");
ball->setPosition(ccp(100,100));
addChild(ball,1);
//CREATE WORLD
b2Vec2 gravity(0, -9.8); //normal earth gravity, 9.8 m/s/s straight down!
bool doSleep = true;
myWorld = new b2World(gravity);
myWorld->SetAllowSleeping(doSleep);
//BODY DEFINITION
myBodyDef.type = b2_dynamicBody; //this will be a dynamic body
myBodyDef.position.Set(0, 20); //set the starting position
myBodyDef.angle = 0; //set the starting angle return true;
myBodyDef.userData=ball;
//CREATE SHAPE
b2CircleShape ballShape;
ballShape.m_p.Set(2.0f,3.0f);
ballShape.m_radius=50.0/PTM_RATIO;
//CREATE BODY
dynamicBody = myWorld->CreateBody(&myBodyDef);
//FIXTURE DEFINITION
b2FixtureDef ballFixtureDef;
ballFixtureDef.shape = &ballShape;
ballFixtureDef.density = 1;
dynamicBody->CreateFixture(&ballFixtureDef);
}
void HelloWorld::update()
{
float32 timeStep = 1/20.0; //the length of time passed to simulate (seconds)
int32 velocityIterations = 8; //how strongly to correct velocity
int32 positionIterations = 3; //how strongly to correct position
myWorld->Step( timeStep, velocityIterations, positionIterations);
}
I am learning box2d basic concepts and i have put my code here. I created a box2d circle shape. now i want to add sprite of ball in that circle shape. I have used myBodyDef.userData=ball; but it is not working .. i used gles-render code to debug draw but in that circle body is different and ball sprite is different. when i applyforce or impluse body works perfectly but dont attached to ball sprite..is any mistake in my code. I want to apply force to ball and ball should bounce according to physics but i can not attach to body plz help me.
Body and sprite looks like this
Here's my version working for V-3.6:
void GamePlayScreen::update(float dt) {
phyWorld->Step(dt, 8, 1);
// Iterate over the bodies in the physics phyWorld
for (b2Body* b = phyWorld->GetBodyList(); b; b = b->GetNext()) {
if (b->GetUserData() != NULL) {
// Synchronize the AtlasSprites position and rotation with the corresponding body
Sprite* sprActor = (Sprite*) b->GetUserData();
sprActor->setPosition(b->GetPosition().x * PTM_RATIO,
b->GetPosition().y * PTM_RATIO);
sprActor->setRotation(-1 * CC_RADIANS_TO_DEGREES(b->GetAngle()));
}
}
}

Cocos2dx, box2d tank

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.

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.

Change PrismaticJoint engine direction

Is it possible to modify the direction of the engine after the joint is created?
This is the definition of a joint:
//Define a prismatic joint
b2PrismaticJointDef jointDef;
b2Vec2 axis = b2Vec2(1.0f, 0.0f);
axis.Normalize(); //Important
jointDef.Initialize(staticBody, body, b2Vec2(0.0f, 0.0f),axis);
jointDef.localAnchorA = b2Vec2(0.0f,0.0f);
jointDef.localAnchorB = body->GetLocalCenter();
jointDef.motorSpeed = 3.0f;
jointDef.maxMotorForce = +200*body->GetMass();
jointDef.enableMotor = true;
jointDef.lowerTranslation = -2.0f;
jointDef.upperTranslation = 3.0f;
jointDef.enableLimit = true;
_horPrismaticJoint = (b2PrismaticJoint*) world->CreateJoint(&jointDef);
Inside CCTouchesBegan I tried to change the force value but it's not working:
_horPrismaticJoint->SetMaxMotorForce(-200.0f);
The cocos distribution is cocos2d-iphone-1.0.1
Yes, you just need to change the speed (not the max force):
joint->SetMotorSpeed( -3.0f );
The max force describes how strong the joint motor is, so it should not be negative.