I'm trying to add Box2d to my C++/SFML platformer game. I have my ground tiles with a b2staticBody. And the player character is b2_dynamicBody.
My usual method to check if player is grounded is to Raycast straight down from centre of sprite to just below the foot level. (NOTE: I do note that SFML is y-down).
For now, I just want the raycast to return true if it hits anything. But it always returns false. I watch the player land on the ground and can walk along the floor and fall off it (ie. The built-in box2d collision is working)
Here is my code (I am brand new to using Box2d in c++, so sorry if it's wrong. There aren't too many good examples to be found online)
void guy::update() {
bool bGrounded = false;
b2RayCastOutput output;
b2RayCastInput input;
input.p1 = bodyPtr->GetPosition();
input.p2 = bodyPtr->GetPosition() + b2Vec2(0, 1.f * Constants::PPU);
input.maxFraction = 1.0f;
b2Fixture* fixture = bodyPtr->GetFixtureList();
std::cout << "p1: " << input.p1.x << " , " << input.p1.y << " / p2: " << input.p2.x << " , " << input.p2.y << std::endl;
std::cout << "sprite pos: " << sprite.getPosition().x << " , " << sprite.getPosition().y << std::endl;
if (fixture->RayCast(&output, input, 0))
{
bGrounded = true;
}
else
{
bGrounded = false;
}
std::cout << "isGrounded: " << bGrounded << std::endl;
}
The console outputs seem ok (ie. p1 and p2 are where I expected them to be), but the bool always returns 0.
Of course I am very open to an improved jumping function. Eventually I want to be able to add the ability to hold the jump button for some time to get a bigger jump. But the only way I can think to start with is checking if the player is touching ground first.
NOTE: Here is the ground Tiles start function (at the bottom you see i CreateFixture():
void Tile::start(size_t x, size_t y, sf::Texture& texture, bool isSolid, b2World* world)
{
worldPtr = world;
bIsSolid = isSolid;
sprite.setTexture(texture, true);
sprite.setOrigin(sprite.getTextureRect().width / 2.f, sprite.getTextureRect().height / 2.f);
sprite.setPosition((float)x * Constants::PPU, (float)y * Constants::PPU);
if (isSolid)
{
bodyDef.position.Set(sprite.getPosition().x, sprite.getPosition().y
);
bodyPtr = worldPtr->CreateBody(&bodyDef);
b2Vec2 topEdge(-1, 0);
box.SetAsBox(sprite.getTextureRect().width / 2.f, sprite.getTextureRect().height / 2.f);
bodyPtr->CreateFixture(&box, 0.f);
}
}
Here is the player start() in case it will help:
void Guy::start(b2World* world)
{
worldPtr = world;
texture.loadFromFile("Textures/guy.png");
sprite.setTexture(texture, true);
sprite.setOrigin(sprite.getTextureRect().width / 2.f, sprite.getTextureRect().height / 2.f);
setPosition(4 * Constants::PPU, 10 * Constants::PPU);
bodyDef.type = b2_dynamicBody;
bodyDef.position.Set(sprite.getPosition().x, sprite.getPosition().y); // TODO: Does this need to be offset?
bodyPtr = worldPtr->CreateBody(&bodyDef);
box.SetAsBox(sprite.getTextureRect().width / 2.f, sprite.getTextureRect().height / 2.f);
fixtureDef.shape = &box;
fixtureDef.density = 65.0f; // TODO Magic numbers
fixtureDef.friction = 0.05f;
bodyPtr->CreateFixture(&fixtureDef);
bodyPtr->SetFixedRotation(true);
}