Box2D - Firing bullet from rotating gun - c++

i have a little trouble as title said: i can't figure out how to shoot the bullet toward the direction the gun is pointing at.
Here's short version code, for my bullet firing:
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.bullet = true;
bd.position = gun->GetPosition();//bullet start at the middle of the gun
m_bullet = m_world->CreateBody(&bd);
m_bullet->CreateFixture(&fd);
m_bullet->ApplyLinearImpulseToCenter( ??? ,true);
At first i thought first param is the direction you want the body go toward so i put in gun->GetWorldPoint(b2Vec2(0.0f,-5.0f)) (middle of the gun's muzzle). Big miss! After a while i thought i should try put in the vector of current gun's rotation degrees b2Vec2 vect = b2Vec2(cos(angle * PI/180), sin(angle * PI/180)); but then the bullet won't fly at all. Now i am all out of ideas. Please, some light.
Full version of code:
public:
b2Body* m_bullet = NULL;
b2Body* gun;
b2RevoluteJoint* joint1;
b2FixtureDef fd;
TestingStuff()
{
{
//body
b2CircleShape circle1;
circle1.m_radius = 1.6f;
fd.shape = &circle1;
fd.density = 1.0f;
fd.filter.groupIndex = -1;
b2BodyDef bd1;
bd1.type = b2_staticBody;
bd1.position.Set(-5.0f, 9.0f);
b2Body* body1 = m_world->CreateBody(&bd1);
body1->CreateFixture(&fd);
//gun
b2PolygonShape box;
box.SetAsBox(0.5f, 5.0f);
fd.shape = &box;
fd.density = 1.0f;
fd.filter.groupIndex = -1;
b2BodyDef bd2;
bd2.type = b2_dynamicBody;
bd2.position.Set(-5.0f, 8.0f);
gun = m_world->CreateBody(&bd2);
gun->CreateFixture(&fd);
//joint
b2RevoluteJointDef jd1;
jd1.Initialize(gun, body1, bd1.position);
jd1.enableMotor = true;
jd1.maxMotorTorque = 90;
jd1.motorSpeed = 180 * DEGTORAD;//DEGTORAD=0.0174532925199432957f
joint1 = (b2RevoluteJoint*) m_world->CreateJoint(&jd1);
}
}
void Keyboard(int key)
{
switch (key)
{
case GLFW_KEY_COMMA:
if (m_bullet != NULL)
{
m_world->DestroyBody(m_bullet);
m_bullet = NULL;
}
{
//bullet
b2CircleShape shape;
shape.m_radius = 0.25f;
fd.shape = &shape;
fd.density = 1;
fd.restitution = 0.05f;
fd.filter.groupIndex = -1;
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.bullet = true;
bd.position = gun->GetPosition();
m_bullet = m_world->CreateBody(&bd);
m_bullet->CreateFixture(&fd);
m_bullet->ApplyLinearImpulseToCenter( ??? ,true);
}
break;
}
}

After a good sleep i found the solution after few more trial and error.
//bullet
float degAngle = joint1->GetJointAngle() * RADTODEG + 180;
b2Vec2 vect = b2Vec2(sin(degAngle* (b2_pi / 180)) * 10, cos(degAngle* (b2_pi / 180)) * 10);
m_bullet->ApplyLinearImpulseToCenter(vect ,true);
The * 10 is to increase the impulse, make the bullet fly faster and farther, for the sake of testing i just make it 10. Notice that this code is just for testing, if you want to make it more realistic, increase the impulse as well as make the bullet go toward the muzzle instead of go toward the vector it had been fired at.

Related

Car body's angle not changing box2D C++

i'm making a side-scrolling car game with box2D.
I'm currently working on the car and it seems that i'm stuck.
The chassis of my car isn't rotating when for example the car is trying to climb a hill. I don't know if its normal or if i should set the angle of the body.
Here's a quick video that shows the problem : https://streamable.com/d802n
This is my code :
b2BodyDef carBox = b2BodyDef();
carBox.position = b2Vec2(bodyCenterPosition.x, bodyCenterPosition.y);
carBox.type = b2_dynamicBody;
car = game->getWorld()->CreateBody(&carBox);
b2PolygonShape carPolygon = b2PolygonShape();
carPolygon.SetAsBox(bodySize.x, bodySize.y);
b2FixtureDef carFix = b2FixtureDef();
carFix.density = 0.0f;
carFix.shape = &carPolygon;
car->CreateFixture(&carFix);
b2PolygonShape headPolygon = b2PolygonShape();
headPolygon.SetAsBox(headSize.x, headSize.y);
for (int i = 0; i < 8; i++) {
headPolygon.m_vertices[i].x -= 8.0f / RATIO;
headPolygon.m_vertices[i].y -= 24.0f / RATIO;
}
b2FixtureDef headFix = b2FixtureDef();
headFix.density = 0.0f;
headFix.shape = &headPolygon;
car->CreateFixture(&headFix);
b2CircleShape circleShape;
circleShape.m_radius = 0.35f;
circleShape.m_p.SetZero();
b2FixtureDef fd;
fd.shape = &circleShape;
fd.density = 1.0f;
fd.friction = 0.9f;
b2BodyDef wheel1Def;
wheel1Def.type = b2_dynamicBody;
wheel1Def.position = b2Vec2(backWheelCenterPosition.x, backWheelCenterPosition.y);
backWheel = game->getWorld()->CreateBody(&wheel1Def);
backWheel->CreateFixture(&fd);
b2BodyDef wheel2Def;
wheel2Def.type = b2_dynamicBody;
wheel2Def.position = b2Vec2(frontWheelCenterPosition.x, frontWheelCenterPosition.y);
frontWheel = game->getWorld()->CreateBody(&wheel2Def);
frontWheel->CreateFixture(&fd);
b2WheelJointDef springDef1;
springDef1.dampingRatio = 50.0f;
springDef1.maxMotorTorque = 1.0f;
springDef1.frequencyHz = 15.0f;
springDef1.motorSpeed = 0.0f;
springDef1.enableMotor = true;
springDef1.Initialize(car, backWheel, backWheel->GetPosition(), sfVecToB2Vec(sf::Vector2f(0.0f, 1.0f)));
backSpring = (b2WheelJoint*) game->getWorld()->CreateJoint(&springDef1);
springDef1.Initialize(car, frontWheel, frontWheel->GetPosition(), sfVecToB2Vec(sf::Vector2f(0.0f, 1.0f)));
frontSpring = (b2WheelJoint*) game->getWorld()->CreateJoint(&springDef1);
It is normal for a body with a fixture having a zero density to behave like an infinite mass. Sounds like that's not what you intended however.
Looking at the code presented, we see that the carFix.density and headFix.density are being set to 0.0f. Set these to a positive non-zero value, like 1.0f, and the dynamic body they're created on should behave more like a physical mass would. That's assuming all of the other fixtures created on that body also have a density that's greater than zero as well.
For a tutorial on fixtures and density, I'd recommend taking a look at iforce2d's Box2D C++ tutorials - Fixtures.
Hope this solves the problem or at least helps.
By the way, I loved the artwork shown in the video!

How do I scale Box2D objects with PPM?

I recently ran into a problem with Box2D where my player was moving at a slow speed. I use LinearImpulse's to move the body but (100, 100) was the fastest it could go.
After researching it a bit, I know that the Box2D body is too large because Box2D uses meters and I'm typing it in pixels. I know I have to scale the bodies using a PPM constant, but it's not quite making sense to me.
I've created a PPM constant and set it to 32.0f.
const float PPM = 32.0f;
Here's how I create the dynamic player body:
void Physics::playerDynamic(float x, float y, float width, float height)
{
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
bodyDef.position.Set(x / PPM, y / PPM);
body = world.CreateBody(&bodyDef);
b2PolygonShape dynamicBox;
dynamicBox.SetAsBox((64.0f) / PPM, (64.0f) / PPM);
b2FixtureDef fixtureDef;
fixtureDef.shape = &dynamicBox;
fixtureDef.filter.categoryBits = CATEGORY_PLAYER;
fixtureDef.filter.maskBits = CATEGORY_PLAYER;
fixtureDef.filter.groupIndex = -1;
body->CreateFixture(&fixtureDef);
world.Step(timeStep, velocityIterations, positionIterations);
posX = x;
posY = y;
bodyType = "player";
}
I understand that I need to scale down the body, which I did by dividing it by the PPM. But now the body is really small and won't collide how I'd like it to.
Here is the function where I apply the impulse to the player body:
void Physics::moveBodies()
{
myCollisionDetection myListener;
world.SetContactListener(&myListener);
if (bodyType != "player")
{
}
else if (bodyType == "player")
{
body->SetAwake(true);
float forceX = 0;
float forceY = 0;
switch (moveState)
{
case MS_UP:
forceY = -50;
break;
case MS_DOWN:
forceY = 50;
break;
case MS_LEFT:
forceX = -50;
break;
case MS_RIGHT:
forceX = 50;
break;
case MS_UPRIGHT:
forceY = -50;
forceX = 50;
break;
case MS_UPLEFT:
forceY = -50;
forceX = -50;
break;
case MS_DOWNRIGHT:
forceY = 50;
forceX = 50;
break;
case MS_DOWNLEFT:
forceY = 50;
forceX = -50;
break;
case MS_STOP:
body->SetLinearVelocity(b2Vec2(0, 0));
}
body->ApplyLinearImpulse(b2Vec2(forceX, forceY ), body->GetWorldCenter(), true);
pos = body->GetPosition();
posX = body->GetPosition().x;
posY = body->GetPosition().y;
}
world.Step(timeStep, velocityIterations, positionIterations);
}
I've been researching this for quite a while and it seems simple but I'm having a hard time applying it to my code.
So what do I do from here? Do I scale the body back up?
I'm also using SDL2 for the graphics. Do I need to change anything with the rendering?

Cocos2d - Moving the Layer/view based on ball movement

My game world space is a rectangle of 4 screen sizes (2 rows x 2 columns )
I am moving the camera based on the movement of a ball. The ball position is set according to the physics engine.
I notice that, sometimes the ball changes direction slightly as the camera is moving to follow the ball.
Initially I thought it was sort of an illusion based on the movement of the camera, but when I draw a path, the line is of crooked at times.
I used some of the code behind the CCFollow implementation code (not CCFollow itself, but the code behind it), for following the ball
(I had issues with CCfollow)
Below is my Tick() function:
————————————————–
- (void)tick:(ccTime) dt {
bool ballMov = false;
CGPoint pos;
CCSprite *ballData;
dt = 1.0 / 60.0f;
world->Step(dt,8, 3 );
for(b2Body *b = world->GetBodyList(); b; b=b->GetNext()) {
if (b->GetUserData() != NULL) {
CCSprite *tempData = (CCSprite *)b->GetUserData();
if (tempData == ball){
ballData = tempData;
ballMov = true;
ballData.position = ccp(b->GetPosition().x * PTM_RATIO, b->GetPosition().y * PTM_RATIO);
}
}
}
//
// Move the layer so we can keep looking at the travelling ball
// Code is similar to CCFollow code with some adjustments
pos = ballPosition;
if(ballMov){
#define CLAMP(x,y,z) MIN(MAX(x,y),z)
pos = ccp(CLAMP(pos.x,leftBoundary,rightBoundary), CLAMP(pos.y,bottomBoundary,topBoundary));
#undef CLAMP
pos = ccpSub(pos, halfScreenSize );
pos.x = - pos.x ;
pos.y = - pos.y ;
//calculate delta move towards the new position
if(gunShot){
CGPoint moveVect;
CGPoint oldPos = [self position];
double dist = ccpDistance(pos, oldPos);
if (dist > 1){
moveVect = ccpMult(ccpSub(pos,oldPos),0.4); //0.05 is the smooth constant.
oldPos = ccpAdd(oldPos, moveVect);
pos = oldPos;
}
}
}
//move towards the ball
[self setPosition:(pos)];
lastPosition = pos;
ballPosition = CGPointMake([ball body]->GetPosition().x * PTM_RATIO, [ball body]->GetPosition().y * PTM_RATIO );
//if ball is out of gameworld space then reset
if (!CGRectContainsPoint ( outerBoundaryRect, ballPosition)){
ball.visible = false ;
[self recreateBody]; //Ball is out of Gameworld, recreate it at the default position
}
}

Joint on the edge of the circle

The green square is the box2d ground.
The bigger circle is connected to the ground by revolute joint, and can be rotated.
All the circles are b2_dynamicBody
I want to joint the smaller circles on the edge or border of the bigger circle as shown below.
Please tell me how can i achieve it and what kind of joint i have to use?
Also when i rotate big circle the small circle should stick at its place.
Go through this code....
// create joint between hook big circle
wheelSprite = [[CCSprite alloc] initWithFile:#"heroWheel.png"];
wheelSprite.visible = FALSE;
wheelSprite.scale = 1.0*hero_size_factor;
wheelSprite.rotation = 0.0;
wheelSprite.anchorPoint = CGPointMake(0.5,0.5);
[layer addChild:wheelSprite z:5];
ballBodyDef.userData = wheelSprite;
//create hook between big circle
hook = world->CreateBody(&ballBodyDef);
b2PolygonShape hookShape;
hookShape.SetAsBox(0.2,0.1);
b2FixtureDef hookDef;
hookDef.shape=&hookShape;
hookDef.density=0.5f*hero_size_factor;
hookDef.friction = 0.0f;
hookDef.restitution = 0.0f;
hookDef.filter.groupIndex=heroGroupIndex;
hook->CreateFixture(&hookDef);
//create circle shape fixture
b2CircleShape wheel1,wheel2,wheel3,wheel4;
float wheelRadius = hero_width/4.0f;
//Create fixture with above shape
b2FixtureDef ballShapeDef1,ballShapeDef2,ballShapeDef3,ballShapeDef4;
wheel1.m_p = b2Vec2(wheelRadius, wheelRadius);
wheel1.m_radius = wheelRadius;
ballShapeDef1.shape = &wheel1;
ballShapeDef1.density = 0.0f;
ballShapeDef1.friction = 0.0f;
ballShapeDef1.restitution = 0.0f;
ballShapeDef1.filter.groupIndex=heroGroupIndex;
hook->CreateFixture(&ballShapeDef1);
wheel2.m_radius = wheelRadius;
wheel2.m_p = b2Vec2(-wheelRadius, -wheelRadius);
ballShapeDef2.shape = &wheel2;
ballShapeDef2.density = 0.0f;
ballShapeDef2.friction = 0.0f;
ballShapeDef2.restitution = 0.0f;
ballShapeDef2.filter.groupIndex=heroGroupIndex;
hook->CreateFixture(&ballShapeDef2);
wheel3.m_radius = wheelRadius;
wheel3.m_p = b2Vec2(wheelRadius,-wheelRadius);
ballShapeDef3.shape = &wheel3;
ballShapeDef3.density = 0.0f;
ballShapeDef3.friction = 0.0f;
ballShapeDef3.restitution = 0.0f;
ballShapeDef3.filter.groupIndex=heroGroupIndex;
hook->CreateFixture(&ballShapeDef3);
wheel4.m_radius = wheelRadius;
wheel4.m_p = b2Vec2(-wheelRadius,wheelRadius);
ballShapeDef4.shape = &wheel4;
ballShapeDef4.density = 0.0f;
ballShapeDef4.friction = 0.0f;
ballShapeDef4.restitution = 0.0f;
ballShapeDef4.filter.groupIndex=heroGroupIndex;
hook->CreateFixture(&ballShapeDef4);
//Create Revolute Joints between hook and big circle
b2RevoluteJointDef revoluteJointDef;
revoluteJointDef.bodyA = hook;
revoluteJointDef.bodyB = Leg;
revoluteJointDef.collideConnected = false;
revoluteJointDef.localAnchorA.Set(0.0,0.0);
revoluteJointDef.localAnchorB.Set(0.0,-(hero_height - 0.1));
revoluteJointDef.referenceAngle = 0;
revoluteJointDef.maxMotorTorque = 5.0*hero_size_factor;
Hero_Motor = (b2RevoluteJoint*)world->CreateJoint(&revoluteJointDef);

Joint in Box2d with cocos2d

I'm new in box2d and I tried to create joint between two body.
I wrote a joint like
b2RevoluteJointDef jointDef;
jointDef.bodyA=worm_head;
jointDef.bodyB=worm_body;
jointDef.lowerAngle = -0.25f * b2_pi; // -45 degrees
jointDef.upperAngle = 0.25f * b2_pi; // 45 degrees
jointDef.enableLimit=true;
jointDef.maxMotorTorque = 10.0f;
jointDef.motorSpeed = 10.0f;
jointDef.enableMotor = true;
joint=(b2DistanceJoint*)_world->CreateJoint(&jointDef);
but body is not moving when head is moving.
my tick method is
- (void)tick:(ccTime) dt {
//we update the position of the b2body based on the sprite position
for (b2Body* body = _world->GetBodyList(); body != nil; body = body->GetNext())
{
if (body->GetUserData() != NULL) {
CCSprite *spritedata = (CCSprite *)body->GetUserData();
if(spritedata.tag==1)
{
b2Vec2 b2Position = b2Vec2(SCREEN_TO_WORLD(spritedata.position.x),
SCREEN_TO_WORLD(spritedata.position.y));
float32 b2Angle = -1 * CC_DEGREES_TO_RADIANS(spritedata.rotation);
body->SetTransform(b2Position,b2Angle);
}
else {
spritedata.position = ccp(body->GetPosition().x * PTM_RATIO,
body->GetPosition().y * PTM_RATIO);
spritedata.rotation = -1 * CC_RADIANS_TO_DEGREES(body->GetAngle());
}
}
}
}
Why is not moving ? How should I change my code ?
In b2RevoluteJointDef , one body is static body and another is dynamic body. My problem is using two dynamic problem. Now, it solved.