Box2D ContactListener Not Detecting Collision - c++

I am trying to detect a collision between a static body and a kinematic body using the b2ContactListener class but my code is not detecting a collision between my two fixtures. I placed an EdgeShape at the top of my kinematic body and made it a fixture to detect a collision with my static body fixture. I am using SFML to draw to the screen and detect keyboard events.
Here is my main function:
int main()
{
Vector2f resolution;
resolution.x = VideoMode::getDesktopMode().width;
resolution.y = VideoMode::getDesktopMode().height;
RenderWindow window(VideoMode(resolution.x, resolution.y),
"Box2D Test", Style::Fullscreen);
Vector2f staticRectSize(100.0f, 20.0f);
Vector2f kinematicRectSize(40.0f, 20.0f);
Event keyBoardEvent;
b2Vec2 gravity(0.0f, 0.0f);
b2World world(gravity);
// Creating static body and fixture
b2BodyDef groundBodyDef;
groundBodyDef.position.Set(100.0f, 150.0f);
b2Body* groundBody = world.CreateBody(&groundBodyDef);
b2PolygonShape groundBox;
groundBox.SetAsBox(50.0f, 10.0f);
groundBody->CreateFixture(&groundBox, 0.0f);
// Creating kinematic body and fixture
b2BodyDef bodyDef;
bodyDef.type = b2_kinematicBody;
bodyDef.position.Set(125.0f, 700.0f);
b2Body* body = world.CreateBody(&bodyDef);
b2PolygonShape kinematicBox;
kinematicBox.SetAsBox(20.0f, 10.0f);
b2FixtureDef fixtureDef;
fixtureDef.shape = &kinematicBox;
fixtureDef.density = 1.0f;
fixtureDef.friction = 0.3f;
body->CreateFixture(&fixtureDef);
// world.Step inputs
float32 timeStep = 1.0f / 60.0f;
int32 velocityIterations = 6;
int32 positionIterations = 2;
RectangleShape staticRect(staticRectSize);
RectangleShape dynamicRect(kinematicRectSize);
b2Vec2 staticPosition = groundBody->GetPosition();
staticRect.setPosition(staticPosition.x, staticPosition.y);
b2Vec2 dynamicPosition = body->GetPosition();
// Creating EdgeShape
b2EdgeShape top;
top.Set(b2Vec2(dynamicPosition.x, dynamicPosition.y), b2Vec2(dynamicPosition.x + 40.0, dynamicPosition.y));
fixtureDef.shape = ⊤
fixtureDef.isSensor = true;
body->CreateFixture(&fixtureDef)->SetUserData("top collision");
// Creating an instance of myContactListener class
myContactListener contactListener;
world.SetContactListener(&contactListener);
while (window.isOpen())
{
world.Step(timeStep, velocityIterations, positionIterations);
dynamicPosition = body->GetPosition();
dynamicRect.setPosition(dynamicPosition.x, dynamicPosition.y);
while (window.pollEvent(keyBoardEvent))
{
if (keyBoardEvent.type == Event::KeyPressed)
{
if (keyBoardEvent.key.code == Keyboard::W)
{
body->SetLinearVelocity(b2Vec2(0, -10));
}
...
window.clear();
window.draw(staticRect);
window.draw(dynamicRect);
window.draw(line);
window.display();
if (Keyboard::isKeyPressed(Keyboard::Escape))
{
break;
}
}
return 0;
}
And here is my MyContactListiner.cpp:
void myContactListener::BeginContact(b2Contact* contact)
{
b2Fixture *fa = contact->GetFixtureA();
b2Fixture *fb = contact->GetFixtureB();
if (fa == NULL || fb == NULL) { return; }
while (1)
{
printf("Collision occurred");
if (Keyboard::isKeyPressed(Keyboard::Escape))
{
break;
}
}
}

Box2D doesn't do collision handling for static bodies directly against other static or kinematic bodies. They're both theoretically of infinite mass for which laws of motion don't seem to make much sense anymore (at least not to me in terms of collisions).
Probably easiest to make the kinematic body a dynamic one instead.
You could alternatively surround one of the bodies with dynamic ones to get the contact listener to fire up. The dynamic bodies can't be made to drive the kinematic or static one it surrounds however in the substep phases without more effort than I think it'd be worth.
Hope this answer helps!

Related

The Gravity in Box2D world

When the gravity is very small, the dynamic object will not move after moving for a short distance. When I run this method, the result is The change of dynamic body' position. When the dynamic body moves to a certain position, it will stop. I do not know why. Maybe the precision problem of floating number?
This is the method I run.
void initializeWorld()
{
// Define the gravity vector.
b2Vec2 gravity(0.0f, 0.011f);
// Construct a world object, which will hold and simulate the rigid bodies.
b2World world(gravity);
// Define the up ground body.
b2BodyDef groundBodyDefUp;
groundBodyDefUp.position.Set(0.0f, 8.0f);
// Define the down ground body.
b2BodyDef groundBodyDefDown;
groundBodyDefDown.position.Set(0.0f, -8.0f);
// Define the left ground body
b2BodyDef groundBodyDefLeft;
groundBodyDefLeft.position.Set(-8.0f,0.0f);
// Define the right ground body
b2BodyDef groundBodyDefRight;
groundBodyDefRight.position.Set(8.0f, 0.0f);
// Call the body factory which allocates memory for the ground body
// from a pool and creates the ground box shape (also from a pool).
// The body is also added to the world.
b2Body* groundBodyUp = world.CreateBody(&groundBodyDefUp);
b2Body* groundBodyDown = world.CreateBody(&groundBodyDefDown);
b2Body* groundBodyLeft = world.CreateBody(&groundBodyDefLeft);
b2Body* groundBodyRight = world.CreateBody(&groundBodyDefRight);
// Define the ground box shape.
b2PolygonShape groundBoxUp;
// The extents are the half-widths of the box.
groundBoxUp.SetAsBox(5.0f, 3.0f);
// Define the ground box shape.
b2PolygonShape groundBoxDown;
// The extents are the half-widths of the box.
groundBoxDown.SetAsBox(5.0f, 3.0f); // Define the ground box shape.
// Define the ground box shape.
b2PolygonShape groundBoxLeft;
// The extents are the half-widths of the box.
groundBoxLeft.SetAsBox(3.0f, 5.0f); // Define the ground box shape.
// Define the ground box shape.
b2PolygonShape groundBoxRight;
// The extents are the half-widths of the box.
groundBoxRight.SetAsBox(3.0f, 5.0f); // Define the ground box shape.
// Add the ground fixture to the ground body.
groundBodyUp->CreateFixture(&groundBoxUp, 0.0f);
/*groundBodyDown->CreateFixture(&groundBoxDown, 0.0f);
groundBodyLeft->CreateFixture(&groundBoxLeft, 0.0f);
groundBodyRight->CreateFixture(&groundBoxRight, 0.0f);*/
// Define the dynamic body. We set its position and call the body factory.
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
bodyDef.position.Set(0.0f, 0.0f);
b2Body* body = world.CreateBody(&bodyDef);
// Define another box shape for our dynamic body.
b2PolygonShape dynamicBox;
dynamicBox.SetAsBox(0.5f, 0.5f);
// Define the dynamic body fixture.
b2FixtureDef fixtureDef;
fixtureDef.shape = &dynamicBox;
// Set the box density to be non-zero, so it will be dynamic.
fixtureDef.density = 1.0f;
// Override the default friction.
fixtureDef.friction = 0.3f;
// Add the shape to the body.
body->CreateFixture(&fixtureDef);
// Prepare for simulation. Typically we use a time step of 1/60 of a
// second (60Hz) and 10 iterations. This provides a high quality simulation
// in most game scenarios.
float32 timeStep = 1.0f / 60.0f;
int32 velocityIterations = 6;
int32 positionIterations = 2;
bool running = true;
while (running)
{
world.Step(timeStep, velocityIterations, positionIterations);
b2Vec2 position = body->GetPosition();
cout << "(" << position.x << "," << position.y <<")"<< endl;
}
}

TimeStep do not iterate | Box2D

i am getting back to box2d after many years of absence and thought to start from zero. on top of that decided to work with the C++ version this time (in the past worked with the Javascript version)
For a reason the very first program described in box2d.org does not run properly. When i compile it i do not get any errors however the result is wrong.
The result is 0.00 4.00 0.00 and remains as such.
But with each iteration of timestep, the position.y should decrease (position.x and angle should remain the same)
#include "include/box2d/box2d.h"
#include <iostream>
#include <stdio.h>
int main(){
b2Vec2 gravity(0.0f, -10.0f); // define the gravity vector
b2World world(gravity); //create the world object
//Creating static Ground Body
b2BodyDef groundBodyDef; //body definition
groundBodyDef.position.Set(0.0f, -10.0f);
b2Body* groundBody = world.CreateBody(&groundBodyDef); // body definition is passed to the world object to create the ground body
b2PolygonShape groundBox; //create a ground polygon.
groundBox.SetAsBox(50.0f, 10.0f); //We use the SetAsBox shortcut to form the ground polygon into a box shape
groundBody->CreateFixture(&groundBox, 0.0f); //creating the shape fixture
//Creating Dynamic Body
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody; //By default bodies are static, so we should set the b2BodyType at construction time to make the body dynamic
bodyDef.position.Set(0.0f, 4.0f);
b2Body* body = world.CreateBody(&bodyDef);
b2PolygonShape dynamicBox; //create a box shap
dynamicBox.SetAsBox(1.0f, 1.0f);
//A dynamic body should have at least one fixture with a non-zero density. Otherwise you will get strange behavior.
b2FixtureDef fixtureDef; // fixture definition using the box
fixtureDef.shape = &dynamicBox;
fixtureDef.density = 1.0f;
fixtureDef.friction = 0.3f;
float timeStep = 1.0f / 60.0f; //Integrators simulate the physics equations at discrete points of time -> ie timeStep
int32 velocityIterations = 6;
int32 positionIterations = 2;
for (int32 i = 0; i < 60; ++i) {
world.Step(timeStep, velocityIterations, positionIterations);
b2Vec2 position = body->GetPosition();
float angle = body->GetAngle();
printf("%4.2f %4.2f %4.2f\n", position.x, position.y, angle);
}
//return 0;
}
Apologies for the noobie question, but cannot find my mistake. i almost copy paste everything!
I actually forgot to include body->CreateFixture(&fixtureDef);

Ball floating in Box2D (SFML)

I'm trying to get Box2D to work with SFML, although I'm having some issues like this:
For some reason ball just stops before hitting the platform. I tried varying the ball's position across x-axis and it falled out of the window,so I guess the drawing is off. Since SFML uses top-left origin for objects, but Box2D uses it's center I had to offset that in the draw functions for box and the ball:
void Ball::draw(sf::RenderWindow & window)
{
circleS.setPosition(sf::Vector2f(body->GetPosition().x - (circle.m_radius
/2),
body->GetPosition().y - (circle.m_radius 2)));
circleS.setRotation(body->GetAngle() * (180.0f / 3.14159f));
window.draw(circleS);
}
void Box::draw(sf::RenderWindow & window)
{
boxShape.setPosition(sf::Vector2f(body->GetPosition().x - (dimension.x / 2),
body->GetPosition().y - (dimension.y / 2)));
boxShape.setRotation(body->GetAngle() * (180.0f / 3.14159f));
window.draw(boxShape);
}
I don't understand why this isn't working,but if it's any help I can include more code. All help is appreciated.
Edit:
I replaced the ball with a box and it worked fine; then I changed up ball back and bottom box was changed to static ball and it just passed through,also here's a snippet of my main function:
RenderWindow window;
window.create(VideoMode(SCREENWIDTH, SCREENHEIGHT), "Pool game");
Event event;
//Setup for Box2D
b2Vec2 gravity(0.0f, 9.81f);
b2World world(gravity);
float32 timeStep = 1.0f / 60.0f;
int32 velocityIterations = 8;
int32 positionIterations = 3;
Box box(b2Vec2(100.0f, 400.0f), b2Vec2(100.0f, 20.0f), Color::Magenta,
world);
Ball ball(b2Vec2(50.0f, 50.0f), 9.0f, Color::Blue, world, true);
//game loop
while (window.isOpen()) {
//window closure
while (window.pollEvent(event)) {
if (event.type == Event::Closed) {
window.close();
}
}
world.Step(timeStep, velocityIterations, positionIterations);
//////// Drawing ////////
window.clear(Color(0,128,0));
//------------------------------------------
box.draw(window);
ball.draw(window);
//------------------------------------------
window.display();
//------------------------------------
}
Edit 2:
Here a header files for Ball and Box classes:
class Box {
//Constructors
public:
Box(b2Vec2 position, b2Vec2 dimension, sf::Color c, b2World &world, bool
isDynamic = false) : dimension(dimension) {
if (isDynamic) bodyDef.type = b2_dynamicBody; else bodyDef.type =
b2_staticBody;
bodyDef.position.Set(position.x , position.y );
body = world.CreateBody(&bodyDef);
dynamicBox.SetAsBox(dimension.x / 2, dimension.y / 2 );
fixtureDef.shape = &dynamicBox;
fixtureDef.density = 1.0f;
fixtureDef.friction = 0.3f;
body->CreateFixture(&fixtureDef);
boxShape.setPosition(sf::Vector2f(body->GetPosition().x - (this-
>dimension.x / 2), body->GetPosition().y - (this->dimension.y / 2)));
boxShape.setSize(sf::Vector2f(this->dimension.x, this->dimension.y));
boxShape.setFillColor(c);
}
~Box() {
body = nullptr;
}
//Functions
public:
void draw(sf::RenderWindow &window);
//Variables
public:
//Box2D
b2BodyDef bodyDef;
b2PolygonShape dynamicBox;
b2FixtureDef fixtureDef;
b2Body* body;
//SFML
sf::RectangleShape boxShape;
b2Vec2 dimension;
};
And also ball :
class Ball {
//Constructors
public:
Ball(b2Vec2 position,float radius, sf::Color c, b2World &world, bool
isDynamic = false) {
if (isDynamic) bodyDef.type = b2_dynamicBody; else bodyDef.type =
b2_staticBody;
bodyDef.position.Set(position.x , position.y );
body = world.CreateBody(&bodyDef);
circle.m_p.Set(position.x,position.y);
circle.m_radius = radius + outlineThickness;
fixtureDef.shape = &circle;
fixtureDef.density = 1.0f;
fixtureDef.friction = 0.3f;
body->CreateFixture(&fixtureDef);
circleS.setPosition(sf::Vector2f(body->GetPosition().x -
(circle.m_radius / 2),body->GetPosition().y - (circle.m_radius / 2)));
circleS.setRadius(radius);
circleS.setOutlineThickness(outlineThickness);
circleS.setOutlineColor(sf::Color::Black);
circleS.setFillColor(c);
}
~Ball() {
body = nullptr;
}
//Functions
public:
void draw(sf::RenderWindow &window);
//Variables
public:
//Box2D
b2BodyDef bodyDef;
b2CircleShape circle;
b2FixtureDef fixtureDef;
b2Body* body;
//SFML
sf::CircleShape circleS;
float outlineThickness = 1.0f;
};

Box2D debug test

I have a problem with Box2d. I created an object (circle) in the center of the screen that rotates to see if I set Box2d well, following the tutorial that I found on internet. The problem is that the circle is created, but I can't rotate despite I followed exactly the tutorial found on internet. This is the code:
file .h:
b2World * _world;
GLESDebugDraw * _debugDraw;
file .mm:
-(void)setupWorld {
b2Vec2 gravity = b2Vec2(0.0f, 0.0f);
bool doSleep = false;
_world = new b2World(gravity, doSleep);
}
-(void)setupDebugDraw {
_debugDraw = new GLESDebugDraw(PTM_RATIO*[[CCDirector sharedDirector] contentScaleFactor]);
_world->SetDebugDraw(_debugDraw);
_debugDraw->SetFlags(b2DebugDraw::e_shapeBit |b2DebugDraw::e_jointBit);
}
-(void)testBox2D {
CGSize winSize = [CCDirector sharedDirector].winSize;
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
bodyDef.position = b2Vec2(winSize.width/2/PTM_RATIO,winSize.height/2/PTM_RATIO);
b2Body *body = _world->CreateBody(&bodyDef);
b2CircleShape circleShape;
circleShape.m_radius = 25.0/PTM_RATIO;
b2FixtureDef fixtureDef;
fixtureDef.shape = &circleShape;
fixtureDef.density = 1.0;
body->CreateFixture(&fixtureDef);
body->ApplyAngularImpulse(0.01);
}
-(void)updateBox2D:(ccTime)dt {
_world->Step(dt, 1, 1);
[self updateBox2D:dt];
}
-(void) draw {
glDisable(GL_TEXTURE_2D); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY);
_world->DrawDebugData();
glEnable(GL_TEXTURE_2D); glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY);
}

in init:
[self setupWorld];
[self setupDebugDraw];
[self testBox2D];
Two problems:
Are you recursively calling updateBox2D? This looks like an infinite loop to me, and I'm surprised that it's not crashing your application.
Instead, you should only call your world's step once (or a few times depending on how you've setup your time step) during your CCScene tick method.
Your next problem is that you're applying a small impulse to your body, but it is only a one-time impulse... Angular impulses are still affected by damping, so the body will not rotate indefinitely by default. To keep your body rotating, you need to set the angular damping to zero:
bodyDef.angularDamping = 0.0f;

Cocos2d draw a polygon using CCSprite

Can you help. Want to draw a polygon (beams at different angles) and apply box 2d body to it. Can you please let me know how to create a CCSprite with a polygon shape
Any examples would help
Cheers
Create Polygon body.
-(void) createDynamicPoly {
b2BodyDef bodyDefPoly;
bodyDefPoly.type = b2_dynamicBody;
bodyDefPoly.position.Set(3.0f, 10.0f);
b2Body *polyBody = world->CreateBody(&bodyDefPoly);
int count = 8;
b2Vec2 vertices[8];
vertices[0].Set(0.0f / PTM_RATIO,0.0f / PTM_RATIO);
vertices[1].Set(48.0f/PTM_RATIO,0.0f/PTM_RATIO);
vertices[2].Set(48.0f/PTM_RATIO,30.0f/PTM_RATIO);
vertices[3].Set(42.0f/PTM_RATIO,30.0f/PTM_RATIO);
vertices[4].Set(30.0f/PTM_RATIO,18.0f/PTM_RATIO);
vertices[5].Set(18.0f/PTM_RATIO,12.0f/PTM_RATIO);
vertices[6].Set(6.0f/PTM_RATIO,18.0f/PTM_RATIO);
vertices[7].Set(0.0f/PTM_RATIO,30.0f/PTM_RATIO);
b2PolygonShape polygon;
polygon.Set(vertices, count);
b2FixtureDef fixtureDefPoly;
fixtureDefPoly.shape = &polygon;
fixtureDefPoly.density = 1.0f;
fixtureDefPoly.friction = 0.3f;
polyBody->CreateFixture(&fixtureDefPoly);
}
Create your sprite
Attach your sprite to the Polygon body via Fixture and UserData
fixtureDefPoly.SetUserData() = spriteObject;
b2Fixture *fixture;
fixture = circleBody->CreateFixture(&fixtureDefPoly);
fixture->SetUserData(#"spriteObject");
Then Iterate the sprite to the body in your update method.
The easiest way is to open an image editor (such as paint for example or photoshop) and create the image you want. The use it in your program.
Also there is a helloWorld scene when creating an xcode application using cocos2d box2d template. It creates a set of squares with a texture.
CGPoint startPt = edge.start ;
CGPoint endpt = edge.end ;
//length of the stick body
float len = abs(ccpDistance(startPt, endpt))/PTM_RATIO;
//to calculate the angle and position of the body.
float dx = endpt.x-startPt.x;
float dy = endpt.y-startPt.y;
//position of the body
float xPos = startPt.x+dx/2.0f;
float yPos = startPt.y+dy/2.0f;
//width of the body.
float width = 1.0f/PTM_RATIO;
b2BodyDef bodyDef;
bodyDef.position.Set(xPos/PTM_RATIO, yPos/PTM_RATIO);
bodyDef.angle = atan(dy/dx);
NSLog([NSString stringWithFormat:#"Setting angle %f",bodyDef.angle]);
CCSprite *sp = [CCSprite spriteWithFile:#"material-wood.png" rect:CGRectMake(0, 0, 12, 12)];
//TODO: fix shape
[self addChild:sp z:1 ];
bodyDef.userData = sp;
bodyDef.type = b2_dynamicBody;
b2Body* body = world->CreateBody(&bodyDef);
b2PolygonShape shape;
b2Vec2 rectangle1_vertices[4];
rectangle1_vertices[0].Set(-len/2, -width/2);
rectangle1_vertices[1].Set(len/2, -width/2);
rectangle1_vertices[2].Set(len/2, width/2);
rectangle1_vertices[3].Set(-len/2, width/2);
shape.Set(rectangle1_vertices, 4);
b2FixtureDef fd;
fd.shape = &shape;
fd.density = 1.0f;
fd.friction = 0.300000f;
fd.restitution = 0.600000f;
body->CreateFixture(&fd);