In the 'jumpability' topic, we discussed how to detect if a player character is on the ground. Another equally common question is "why does my character get stuck when moving along flat ground?". This typically happens when the ground consists of multiple shapes (polygon or edge shapes) placed adjacently to create a flat surface, with a rectangular character shape moving along it.

This often results from level layouts defined as tiles in a fixed grid - while convenient for many purposes, this approach is somewhat sub-optimal for representing smooth surfaces.

Why does the character get stuck?

dynamic box moving right on a surface made of two aligned rectangles

Box2D handles collisions between two shapes by calculating overlap and determining the quickest separation path. Key point: collisions are always resolved between exactly two shapes. Collisions are not resolved in threes, neither are they resolved in fours. Of course, five is right out.

So there are actually two individual collisions going on which will be resolved separately: player standing on the left rectangle vs touching the corner of the right rectangle

In each of these the quickest way to push the overlapping fixtures apart is calculated. In the case on the left the solution is almost certainly to push the 'player' up and the ground down:

force arrows pointing up for the player and down for the ground

Corner vs corner collisions are more complex: a small change in the position of the fixtures could cause a big difference in the resulting impulse that is calculated to separate them. Also, as the player body moves, it slightly bounces up and down from collision responses:

movement arrows indicate many small bounces as the player moves

At the moment the player collides with the new ground box on the right, one of two things could happen. Zooming in close to the corner we can see two possibilities.

left image: the overlap area is wider, forces point vertically up and down, right image: overlap area is taller, forces point left and right

Solutions

1. Clipping Polygon Corners

Clipping corners of either the player or ground polygons can improve collision response:

the bottom corners of the player are clipped off

Box2D V3 has the ability to round any corners: every polygon has a radius which can be zero for sharp corners, or larger to make the corners rounded.

Using circular shapes for the player provides even better results but may still bounce a little when crossing the joints.

2. Chain Edge Shapes

Chain Edge shapes significantly improve upon separate polygons. They consist of a series of connected lines between points and experience fewer collision issues than polygons.

One nice thing about replacing polygons with edges is that you no longer need to worry about keeping them convex and within 8 vertices as you do with polygons. And when you have an area of ground which should be perfectly flat, it's trivial to replace many adjacent edges with a single large edge.

3. Ghost Vertices

Ghost vertices allow smooth segments to have additional vertices that don't participate in collision detection but influence collision response:

v0 connects to v1 with a dotted line, v1 - v2 a solid line, v2 - v3 a dotted line

Implementation example:


// Create a chain to hold the smooth segments
const chainId = 1;
const chainShape = new b2ChainShape();
chainShape.id = chainId;

// take a look at the side-view car example for how to use chain edges to create an interesting terrain

// Create a smooth segment shape with ghost vertices
const segmentDef = new b2SmoothSegment();
segmentDef.segment = new b2Segment(new b2Vec2(v1.x, v1.y), new b2Vec2(v2.x, v2.y));
segmentDef.ghost1 = new b2Vec2(v0.x, v0.y);
segmentDef.ghost2 = new b2Vec2(v3.x, v3.y);

// Create the shape
const shapeDef = b2DefaultShapeDef();
const shapeId = b2CreateSegmentShape(bodyId, shapeDef, segmentDef);

Important Considerations

When using ghost vertices, ensure segments aren't too small compared to colliding objects. If both v2 and v3 vertices end up inside the player shape, the ghost system may fail.

many small edges following a complex terrain

Credits

This tutorial is adapted from an original piece of work created by Chris Campbell and is used under license.