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.
Related
I'm doing this video tutorial:
http://www.spritebuilder.com/getting-started/
Everything works fine but the birds im shooting have no speed. They just fall down.
Hope you guys have a solution! Thanks in advance!
Here is my lauchBird function:
-(void)launchBird:(id)sender
{
//calc rotation
float rotationRadians = CC_DEGREES_TO_RADIANS(_launcher.rotation);
//vector for rotation
CGPoint directionVector = ccp(sinf(rotationRadians), cosf(rotationRadians));
CGPoint ballOffset = ccpMult(directionVector, 50);
//ball (bird)
CCNode* ball = [CCBReader load:#"Bird"];
ball.position = ccpAdd(_launcher.position, ballOffset);
//add ball to physicsNode
[_physicsNode addChild:ball];
//make impulse and apply force
CGPoint force = ccpMult(directionVector, 50000);
[ball.physicsBody applyForce:force];
}
As suggested by Allen S, you need to add a physicsBody to the ball. You can do this by
int padding = 5;
CGFloat radius = 0.5*(ball.contentSize.width - padding);
//create a physics body
CCPhysicsBody* body = [CCPhysicsBody bodyWithCircleOfRadius:radius andCenter:ball.anchorPointInPoints];
body.density = 1.0;
body.friction = 0.5f;
ball.physicsBody = body; //assign the created body to the node's physicsBody property.
Play around with the physicsBody's properties(density,friction,mass,elasticity...) to get the desired effect.
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
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.
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.
Using Box2d, how to create a rubber thread (rubber band / elastic rope) like Parachute Ninja (ZeptoLab)?
-(void) CreateElasticRope {
//=======Params
// Position and size
b2Vec2 lastPos = b2Vec2(4,4); //set position first body
float widthBody = 0.35;
float heightBody = 0.1;
// Body params
float density = 0.05;
float restitution = 0.5;
float friction = 0.5;
// Distance joint
float dampingRatio = 0.85;
float frequencyHz = 10;
// Rope joint
float kMaxWidth = 1.1;
// Bodies
int countBodyInChain = 10;
b2Body* prevBody;
//========Create bodies and joints
for (int k = 0; k < countBodyInChain; k++) {
b2BodyDef bodyDef;
if(k==0 || k==countBodyInChain-1) bodyDef.type = b2_staticBody; //first and last bodies are static
else bodyDef.type = b2_dynamicBody;
bodyDef.position = lastPos;
lastPos += b2Vec2(2*widthBody, 0); //modify b2Vect for next body
bodyDef.fixedRotation = YES;
b2Body* body = world->CreateBody(&bodyDef);
b2PolygonShape distBodyBox;
distBodyBox.SetAsBox(widthBody, heightBody);
b2FixtureDef fixDef;
fixDef.density = density;
fixDef.restitution = restitution;
fixDef.friction = friction;
fixDef.shape = &distBodyBox;
body->CreateFixture(&fixDef);
if(k>0) {
//Create distance joint
b2DistanceJointDef distJDef;
b2Vec2 anchor1 = prevBody->GetWorldCenter();
b2Vec2 anchor2 = body->GetWorldCenter();
distJDef.Initialize(prevBody, body, anchor1, anchor2);
distJDef.collideConnected = false;
distJDef.dampingRatio = dampingRatio;
distJDef.frequencyHz = frequencyHz;
world->CreateJoint(&distJDef);
//Create rope joint
b2RopeJointDef rDef;
rDef.maxLength = (body->GetPosition() - prevBody->GetPosition()).Length() * kMaxWidth;
rDef.localAnchorA = rDef.localAnchorB = b2Vec2_zero;
rDef.bodyA = prevBody;
rDef.bodyB = body;
world->CreateJoint(&rDef);
} //if k>0
prevBody = body;
} //for -loop
}
I use distance and rope Joints, set different values of parameters dampingRatio and frequencyHz, but the effect is far from being an example (my thread for a long time coming to original state, and not so elastic.).
You can simulate springs by applying forces. At each timestep update the forces on the connected bodies (wake the bodies up if necessary too). If one of the bodies is the ground (or a static body) then you don't need to apply any force to the ground just the dynamic body.
A regular spring would apply both tension and compression forces (pull and push) depending on the deflection. In your case you have a bungee so there would be no compression force just tension (pull).
This is the formula you need:
F = K * x
Where F is the force, K is the spring stiffness (force/deflection), and x is the deflection. Deflection is computed as the difference between the initial length and the current length (the distance between connection points). The sign of the F determines if it is pulling or pushing. Once you compute F then you need to apply it along the line connecting two spring connection points. To satisfy force balance you need to apply this force in opposing directions (one of the bodies gets positive the other one gets negative force). This is because Sir Newton says so.
Here is an example (works with pyBox2D but you can easily convert this to C++)
You need spring objects with some properties. Your spring objects need to know their initial lengths, stiffness, body1, body2, connection coordinates (b1x, b1y, b2x, b2y (in local coordinates))
In your case you need to check if length < spr.initialLength, if this is True then you don't apply any force.
body1 = spr.box2DBody1
body2 = spr.box2DBody2
pA = body1.GetWorldPoint(b2Vec2(spr.box2Db1x, spr.box2Db1y))
pB = body2.GetWorldPoint(b2Vec2(spr.box2Db2x, spr.box2Db2y))
lenVector = pB - pA
length = lenVector.Length()
deltaL = length - spr.initialLength
force = spr.K * deltaL
#normalize the lenVector
if length == 0:
lenVector = b2Vec2(0.70710678118654757, 0.70710678118654757)
else:
lenVector = b2Vec2(lenVector.x / length, lenVector.y / length)
sprForce = b2Vec2(lenVector.x * force, lenVector.y * force)
body1.ApplyForce(sprForce, pA)
body2.ApplyForce(-sprForce, pB)
I very much doubt they are using any joints there. They are probably just taking the distance between the current position of the ninja guy, and the middle of the two posts, to calculate a direction and starting impulse... and just drawing two lines between the posts and the ninja guy.
The best physics implementation added to games I have seen was done by a guy with an engineering degree. He used the calculations you would do in physics / engineering translated into C++. Everything from simple gravity, recoil, thrust, to rotational velocities caused by incidental explosions. All the math was separated into a module that was distinct from the animation.
I would suggest looking up formulas for properties of elastics, and also consider that you have three situations for the elastic band:
1) A shaped force is being applied to stretch it back
2) The shape is now driven by the elastic properties of the band
3) The shape is no longer touching the band, and the band is loosely oscillating by its own weight and inertia
The closer you get to using the true physics calculations, the more realistic it will appear. I'm sure you can fudge it to make it easier on yourself, but humans are inherently good at seeing fakeness.