Box2D 3.1.0
A 2D physics engine for games
|
Box2D provides geometric types and functions. These include:
The collision interface is designed to be usable outside of rigid body simulation. For example, you can use the dynamic tree for other aspects of your game besides physics.
However, the main purpose of Box2D is to be a rigid body physics engine. So the collision interface only contains features that are also useful in the physics simulation.
Shape primitives describe collision geometry and may be used independently of physics simulation. At a minimum, you should understand how to create primitives that can be later attached to rigid bodies.
Box2D shape primitives support several operations:
Circles have a center and radius. Circles are solid.
You can also initialize a circle and other structures inline. This is an equivalent circle:
Capsules have two center points and a radius. The center points are the centers of two semicircles that are connected by a rectangle.
Box2D polygons are solid convex polygons. A polygon is convex when all line segments connecting two points in the interior do not cross any edge of the polygon. Polygons are solid and never hollow. A polygon must have 3 or more vertices.
Polygons vertices are stored with a counter clockwise winding (CCW). We must be careful because the notion of CCW is with respect to a right-handed coordinate system with the z-axis pointing out of the plane. This might turn out to be clockwise on your screen, depending on your coordinate system conventions.
The polygon members are public, but you should use initialization functions to create a polygon. The initialization functions create normal vectors and perform validation.
Polygons in Box2D have a maximum of 8 vertices, as controlled by b2_maxPolygonVertices. If you have more complex shapes, I recommend to use multiple polygons.
There are a few ways to create polygons. You can attempt to create them manually, but this is not recommended. Instead there are several functions provided to create them.
For example if you need a square or box you can use these functions:
The values provided to these functions are extents, which are half-widths or half-heights. This corresponds with circles and capsules using radii instead of diameters.
Box2D also supports rounded polygons. These are convex polygons with a thick rounded skin.
If you want a box that is not centered on the body origin, you can use an offset box.
If you want a more general convex polygon, you can compute the hull using b2ComputeHull()
. Then you can create a polygon from the hull. You can make this rounded or not.
If you have an automatic process for generating convex polygons, you may feed a degenerate set of points to b2ComputeHull()
. You should check that the hull was created successfully before creating the polygon or you will get an assertion.
Degenerate points may be coincident and/or collinear. For the hull to be viable, the enclosed area must be sufficiently positive.
Segments are line segments. Segment shapes can collide with circles, capsules, and polygons but not with other line segments. The collision algorithms used by Box2D require that at least one of two colliding shapes has sufficiently positive area. Segment shapes have no area, so segment-segment collision is not possible.
In many cases a game environment is constructed by connecting several segment shapes end-to-end. This can give rise to an unexpected artifact when a polygon slides along the chain of segments. In the figure below there is a box colliding with an internal vertex. These ghost collisions are caused when the polygon collides with an internal vertex generating an internal collision normal.
If edge1 did not exist this collision would seem fine. With edge1 present, the internal collision seems like a bug. But normally when Box2D collides two shapes, it views them in isolation.
b2ChainSegment
provides a mechanism for eliminating ghost collisions by storing the adjacent ghost vertices. Box2D uses these ghost vertices to prevent internal collisions.
The Box2D algorithm for dealing with ghost collisions only supports one-sided collision. The front face is to the right when looking from the first vertex towards the second vertex. This matches the counter-clockwise winding order used by polygons.
Chain segments use a concept called ghost vertices that Box2D can use to eliminate ghost collisions.
These ghost vertices must align with vertices of neighboring chain segments, making them tedious and error-prone to setup.
Chain segments are not created directly. Instead, you can create chains of line segments. See b2ChainDef
and b2CreateChain()
.
You can perform a geometric queries on a single shape.
You can test a point for overlap with a shape. You provide a transform for the shape and a world point.
See also b2PointInCircle()
and b2PointInPolygon()
.
You can cast a ray at a shape to get the point of first intersection and normal vector.
Caution: No hit will register if the ray starts inside a convex shape like a circle or polygon. This is consistent with Box2D treating convex shapes as solid.
You can also cast a shape at another shape. This uses an abstract way of describing the moving shape. It is represented as a point cloud with a radius. This implies a convex shape even if the input data is not convex. The internal algorithm (GJK) will essentially only use the convex portion.
Even more generic, you can use b2ShapeCast()
to linearly cast one point cloud at another point cloud. All shape cast functions use this internally.
b2ShapeDistance()
function can be used to compute the distance between two shapes. The distance function needs both shapes to be converted into a b2DistanceProxy
(which are point clouds with radii). There is also some caching used to warm start the distance function for repeated calls. This can improve performance when the shapes move by small amounts.
If two shapes are moving fast, they may tunnel through each other in a single time step.
The b2TimeOfImpact()
function is used to determine the time when two moving shapes collide. This is called the time of impact (TOI). The main purpose of b2TimeOfImpact()
is for tunnel prevention. Box2D uses this internally to prevent moving objects from tunneling through static shapes.
The b2TimeOfImpact()
identifies an initial separating axis and ensures the shapes do not cross on that axis. This process is repeated as shapes are moved closer together, until they touch or pass by each other.
The TOI function might miss collisions that are clear at the final positions. Nevertheless, it is very fast and adequate for tunnel prevention.
It is difficult to put a restriction on the rotation magnitude. There may be cases where collisions are missed for small rotations. Normally, these missed rotational collisions should not harm game play. They tend to be glancing collisions.
The function requires two shapes (converted to b2DistanceProxy
) and two b2Sweep
structures. The sweep structure defines the initial and final transforms of the shapes.
You can use fixed rotations to perform a shape cast. In this case, the time of impact function will not miss any collisions.
Box2D has functions to compute contact points for overlapping shapes. If we consider circle-circle or circle-polygon, we can only get one contact point and normal. In the case of polygon-polygon we can get two points. These points share the same normal vector so Box2D groups them into a manifold structure. The contact solver takes advantage of this to improve stacking stability.
Normally you don't need to compute contact manifolds directly, however you will likely use the results produced in the simulation.
The b2Manifold
structure holds a normal vector and up to two contact points. The contact points store the normal and tangential (friction) impulses computed in the rigid body simulation.
b2DynamicTree
is used by Box2D to organize large numbers of shapes efficiently. The object does not know directly about shapes. Instead it operates on axis-aligned bounding boxes (b2AABB
) with user data integers.
The dynamic tree is a hierarchical AABB tree. Each internal node in the tree has two children. A leaf node is a single user AABB. The tree uses rotations to keep the tree balanced, even in the case of degenerate input.
The tree structure allows for efficient ray casts and region queries. For example, you may have hundreds of shapes in your scene. You could perform a ray cast against the scene in a brute force manner by ray casting each shape. This would be inefficient because it does not take advantage of shapes being spread out. Instead, you can maintain a dynamic tree and perform ray casts against the tree. This traverses the ray through the tree skipping large numbers of shapes.
A region query uses the tree to find all leaf AABBs that overlap a query AABB. This is faster than a brute force approach because many shapes can be skipped.
Normally you will not use the dynamic tree directly. Rather you will go through the b2World
functions for ray casts and region queries. If you plan to instantiate your own dynamic tree, you can learn how to use it by looking at how Box2D uses it. Also see the DynamicTree
sample.