3
\$\begingroup\$

I am creating a simple OpenGL C++ game. I have a main character (green box) and some static objects (red boxes) positioned as stairs.

The problem is as green box is descending down the stairs, it overlaps with the edges of red boxes. You can see in the gif that bottom right of green box intersects with top left of red boxes.

enter image description here

It's not the same with Unity. If the character collides, it rotates giving a much more natural feel.

enter image description here

Character.cpp (Dynamic Object)

m_Position = glm::vec2(800.0f, 800.0f);
m_Rotation = 45.0f;
m_Scale = 50.0f;

b2BodyDef def;
def.type = b2_dynamicBody;
def.position.Set(Util::PixelToMeter(m_Position.x), Util::PixelToMeter(m_Position.y));

m_Body = m_PhysicsWorld.CreateBody(&def);

b2PolygonShape shape;
shape.SetAsBox(Util::PixelToMeter(m_Scale / 2.0f), Util::PixelToMeter(m_Scale / 2.0f));

b2Fixture* fixture = m_Body->CreateFixture(&shape, 1.0f);
fixture->SetFriction(0.3f);

And then on onRender:

const auto& newPosition = m_Body->GetPosition();
m_Position.x = Util::MeterToPixel(newPosition.x);
m_Position.y = Util::MeterToPixel(newPosition.y);
m_Rotation = m_Body->GetAngle();

Wall.cpp (Static Object)

m_Position = glm::vec2(position.x, position.y);
m_Rotation = 0.0f;
m_Scale = 50.0f;

b2BodyDef def;
def.type = b2_staticBody;
def.position.Set(Util::PixelToMeter(m_Position.x), Util::PixelToMeter(m_Position.y));

m_Body = m_PhysicsWorld.CreateBody(&def);

b2PolygonShape shape;
shape.SetAsBox(Util::PixelToMeter(m_Scale / 2.0f), Util::PixelToMeter(m_Scale / 2.0f));

m_Body->CreateFixture(&shape, 0.0f);

This is my repository: https://github.com/axelthat/OpenGLBox2D

Physics world is created here: https://github.com/axelthat/OpenGLBox2D/blob/main/SuperMarioBrosClone/src/Game.cpp

Red box: https://github.com/axelthat/OpenGLBox2D/blob/main/SuperMarioBrosClone/src/Wall.cpp

Green box: https://github.com/axelthat/OpenGLBox2D/blob/main/SuperMarioBrosClone/src/Character.cpp

What am I doing wrong?

\$\endgroup\$

1 Answer 1

3
+100
\$\begingroup\$

The main problem is the drawn rotation in degrees does not match the simulated body's rotation in radians.

Your initial rotation of 45 is never applied to the body, so it is falling flat.

Box2D uses radians for angles. Ref 1

Your renderer draw code expects degrees:

glm::radians(rotation)

You are sending it an angle in radians in OnRender:

m_Rotation = m_Body->GetAngle();

I understand that degrees are easier to work with, but radians have a lot of beneficial properties in Trigonometry, and are the only angular "unit" used by computer operations and matrices.

In Unity3D and Unreal Engine, any angles entered into the widgets are converted then stored and used in radians.

If I may suggest your code do the same(it will save a lot of multiplications in the long run):

m_RenderData.shader->SetMatrix4(
        "u_Model",
        glm::translate(glm::mat4(1.0f), { position.x, position.y, 0.0f }) *
        glm::rotate(glm::mat4(1.0f), rotation, { 0.0f, 0.0f, 1.0f }) *
        glm::scale(glm::mat4(1.0f), { scale, scale, 0.0f })
    );

The collision between the Character and Wall have zero friction since the wall fixture has no friction. This is evidenced by the slow horizontal movement that should not exist at all(see below for the explanation of the leftward movement.)

So if one fixture has zero friction then the contact will have zero friction. Ref 2

The change the last line of Wall.cpp given as above to:

b2Fixture* fixture = m_Body->CreateFixture(&shape, 1.0f); // density is irrelevant on static bodies
fixture->SetFriction(0.3f);

Once you fix the friction, you will notice your box no longer slides and falls off of the ledge.

The leftward movement was a result of the iterative and precision limits of the torque calculations combined with a zero friction calculation.(a very small amount(near zero) of the torque moment was applied to the overhang in your code causing the linear sliding effect)

Near Zero and +/- Infinity inside of physics simulations tends to blow up the internal calculations(hence the unneeded 1 in the density field). Luckily Box2D does provide limits.


You must move the center of mass to the left so it is over the edge of the step. Your animation shows it landing flat.

There are three other considerations:

  1. Gravity - Unit dependent(lower on your image than the Unity version)
  2. Angular dampening - needs to be small but above 0 to stabilize the calculations
  3. Restitution - a tiny, think 3-30 * double.epsilon, value will allow the simulation space to rotate in the next frame more smoothly without secondary collisions during the iterative process.
\$\endgroup\$
1
  • \$\begingroup\$ Lol totally missed the fact that the rotation is in degrees. Thank you for in-depth explanation. Greatly appreciated. \$\endgroup\$
    – Axel
    Commented Oct 17, 2023 at 3:52

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .