Help us shape the future of Go! Take the 2026 Go Developer Survey

dbox2d

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 31, 2026 License: MIT Imports: 2 Imported by: 0

README

dbox2d

dbox2d is a deterministic 2D rigid body solver for Go. It computes with signed Q32.32 fixed-point arithmetic from fixed, so equal inputs produce the same result bits on every supported architecture, on every run.

The module is pre-v1. Its import path and its API may change before the first stable release. It requires Go 1.26.4 or newer.

The port is in its foundation stage: worlds, bodies, shapes, mass computation, a determinism checksum and an integration-only Step. Contact and joint solving are not ported yet. PORTING.md tracks what has landed.

Fidelity contract

dbox2d is a port of Box2D v3.1.1, not a rewrite. It keeps the upstream file decomposition, the upstream names without the b2 prefix, and the upstream order of operations. Years of edge-case work are the reason the port exists, and a faithful port lets each function be compared against its upstream counterpart.

The port preserves the upstream formulation, not its output bits. Box2D computes in floating point; dbox2d computes in fixed point, so the two produce different trajectories. Every place where fixed-point arithmetic forbids the original line is a divergence, and every divergence carries a reason and a test in DIVERGENCES.md. PORTING.md maps each upstream file to its Go counterpart and to how faithful that port is.

dbox2d is not affiliated with the Box2D project, and it is neither endorsed nor supported by its author. Report defects here, never upstream.

Install

go get github.com/dhannyell/dbox2d

Performance

Fixed point buys determinism and pays in speed. The repository measures that price with two benchmark pairs in bench_test.go. Each pair runs the Q32.32 code against a line-by-line float64 mirror of the same code, which stands in for the floating-point formulation of the reference.

Benchmark (1024 bodies, amd64) Median time Allocations
Full Step, 4 sub-steps, Q32.32 ~0.50 ms 0
Full Step, 4 sub-steps, float64 mirror ~0.11 ms 0
Velocity integration only, Q32.32 ~41 µs 0
Velocity integration only, float64 mirror ~4.8 µs 0

The composite number is the honest one: a full Step runs about 4.4× slower than its float64 mirror, at about 0.5 µs per body, and allocates nothing after the world is built. The micro pair explains where the cost lives: the velocity integrator alone pays about 8.5×, because each Q division is a 128-by-64-bit hardware divide and the damping factor takes three of them per body. The rest of the pipeline, with its square roots, normalizations and bounds work, dilutes that hot spot.

These numbers come from one machine (Ryzen 7 5800X3D) and one snapshot of the code. Run go test -run "^$" -bench . -benchmem for your own.

Reference source

The upstream C source sits in this repository on the branch reference/box2d-v3.1.1, with the upstream history up to that tag. The branch never merges into main, it never builds, and no Go file imports it. It exists so that the porting work has one pinned, versioned reference that still answers why a line looks the way it does:

git show reference/box2d-v3.1.1:src/manifold.c
git blame reference/box2d-v3.1.1 -- src/manifold.c

The upstream tags are deliberately absent. Go derives module versions from tags, so an upstream tag here would publish a version of this module that points at C source.

The Go module zip contains only the tagged tree, so go get never downloads the reference source.

License

MIT. This is a derivative work of Box2D, which is also MIT. See LICENSE.

Documentation

Overview

Package dbox2d implements a deterministic 2D rigid body solver.

The package computes with the Q32.32 fixed-point arithmetic of github.com/dhannyell/fixed. Equal inputs produce the same result bits on every supported architecture, on every run. A world therefore survives a snapshot, a replay and a rollback without drift.

Fidelity

The package is a port of Box2D v3.1.1. It keeps the upstream file decomposition, the upstream names without the b2 prefix, and the upstream order of operations. The port preserves the upstream formulation, not its output bits. Box2D computes in floating point, so the two libraries produce different trajectories.

Fixed-point arithmetic forbids some upstream lines, such as an epsilon tuned for float or a stopping criterion that depends on it. Each such place is a recorded divergence with a reason and a test.

Angles

An angle is a turn, not a radian, because a turn reduces without pi. The solver stores an orientation as a github.com/dhannyell/fixed.Rot sine and cosine pair, never as an angle.

IDs

WorldId, BodyId, ShapeId, ChainId and JointId are opaque handles. Their zero values are null, and IDs of the same type can be compared with ==. Pass them by value and obtain them from package functions; constructing a packed value by hand may make it refer to whatever occupies that slot.

Accumulation

Saturated addition is not associative near the range limits. The solver keeps a fixed accumulation order for that reason. An executor that changes the order changes the result bits, so it must prove bit equality against the scalar path.

Index

Constants

View Source
const (
	DefaultCategoryBits uint64 = 1
	DefaultMaskBits     uint64 = math.MaxUint64
)

Default filter bits. upstream B2_DEFAULT_CATEGORY_BITS, B2_DEFAULT_MASK_BITS

View Source
const MaxPolygonVertices = 8

MaxPolygonVertices is the vertex limit of a convex polygon. Raising it costs performance even for shapes that use fewer vertices.

Variables

This section is empty.

Functions

func AABBContains

func AABBContains(a, b AABB) bool

AABBContains reports whether a fully contains b.

func AABBOverlaps

func AABBOverlaps(a, b AABB) bool

AABBOverlaps reports whether a and b overlap.

func Checksum

func Checksum(worldId WorldId) uint64

Checksum folds the complete deterministic state of a world into one integer. Application data and internal ids are excluded because they do not affect simulation. Bodies and shapes use commutative folds, so equivalent worlds do not depend on creation order.

func ClampInt

func ClampInt(a, lower, upper int) int

ClampInt returns a limited to the range [lower, upper].

func DestroyBody

func DestroyBody(bodyId BodyId)

DestroyBody destroys a body. Every shape attached to it goes away too.

func DestroyShape

func DestroyShape(shapeId ShapeId, updateBodyMass bool)

DestroyShape destroys a shape. Pass updateBodyMass true to recompute the mass of the body from the remaining shapes.

func DestroyWorld

func DestroyWorld(worldId WorldId)

DestroyWorld destroys a world and every body and shape in it.

func GetLengthAndNormalize

func GetLengthAndNormalize(v Vec2) (Q, Vec2)

GetLengthAndNormalize returns the length of v and the unit vector with the same direction. The zero vector returns a zero length and the zero vector.

func IsNormalized

func IsNormalized(a Vec2) bool

IsNormalized reports whether a has unit length.

func IsNormalizedRot

func IsNormalizedRot(q Rot) bool

IsNormalizedRot reports whether q has unit length.

func IsValidAABB

func IsValidAABB(a AABB) bool

IsValidAABB reports whether a is usable and not inverted.

func IsValidPlane

func IsValidPlane(a Plane) bool

IsValidPlane reports whether a has a unit normal and a usable offset.

func IsValidQ

func IsValidQ(a Q) bool

IsValidQ reports whether a is a usable value. Fixed-point arithmetic has no NaN and no infinity; it saturates instead, so a saturated value is the signal that a computation left the representable range.

func IsValidRay

func IsValidRay(input *RayCastInput) bool

IsValidRay reports whether a ray cast input is usable.

func IsValidRotation

func IsValidRotation(q Rot) bool

IsValidRotation reports whether q is a usable and normalized rotation.

func IsValidVec2

func IsValidVec2(v Vec2) bool

IsValidVec2 reports whether v is a usable vector.

func PointInCapsule

func PointInCapsule(point Vec2, shape *Capsule) bool

PointInCapsule reports whether a point overlaps a capsule in local space.

func PointInCircle

func PointInCircle(point Vec2, shape *Circle) bool

PointInCircle reports whether a point overlaps a circle in local space.

func Step

func Step(worldId WorldId, timeStep Q, subStepCount int)

Step advances the simulation by timeStep, split into subStepCount sub-steps. The reference recommends a fixed time step and 4 sub-steps. It corresponds to b2World_Step in src/world.c.

func StoreBodyId

func StoreBodyId(id BodyId) uint64

StoreBodyId packs a body id into a uint64.

func StoreChainId

func StoreChainId(id ChainId) uint64

StoreChainId packs a chain id into a uint64.

func StoreJointId

func StoreJointId(id JointId) uint64

StoreJointId packs a joint id into a uint64.

func StoreShapeId

func StoreShapeId(id ShapeId) uint64

StoreShapeId packs a shape id into a uint64.

func StoreWorldId

func StoreWorldId(id WorldId) uint32

StoreWorldId packs a world id into a uint32.

func ValidateHull

func ValidateHull(hull *Hull) bool

ValidateHull reports whether a hull is convex and free of collinear points. It is expensive, so it does not belong in a running simulation.

Types

type AABB

type AABB struct {
	LowerBound Vec2
	UpperBound Vec2
}

AABB is an axis-aligned bounding box.

func AABBUnion

func AABBUnion(a, b AABB) AABB

AABBUnion returns the smallest box that contains a and b.

func ComputeCapsuleAABB

func ComputeCapsuleAABB(shape *Capsule, xf Transform) AABB

ComputeCapsuleAABB returns the bounding box of a transformed capsule.

func ComputeCircleAABB

func ComputeCircleAABB(shape *Circle, xf Transform) AABB

ComputeCircleAABB returns the bounding box of a transformed circle.

func ComputePolygonAABB

func ComputePolygonAABB(shape *Polygon, xf Transform) AABB

ComputePolygonAABB returns the bounding box of a transformed polygon.

func ComputeSegmentAABB

func ComputeSegmentAABB(shape *Segment, xf Transform) AABB

ComputeSegmentAABB returns the bounding box of a transformed segment.

func MakeAABB

func MakeAABB(points []Vec2, radius Q) AABB

MakeAABB returns the box that bounds a set of circles of the given radius. It panics when points is empty.

type BodyDef

type BodyDef struct {
	// The body type: static, kinematic or dynamic.
	Type BodyType

	// The initial world position. Create a body at its final position:
	// creating it at the origin and moving it costs nearly twice as much.
	Position Vec2

	// The initial world rotation. Use MakeRot for an angle in turns.
	Rotation Rot

	// The initial linear velocity of the body origin, usually in meters per
	// second.
	LinearVelocity Vec2

	// The initial angular velocity, in turns per second. The reference uses
	// radians per second; an angle is a turn in this package.
	AngularVelocity Q

	// Linear damping reduces the linear velocity. A value larger than 1 is
	// valid but grows sensitive to the time step. Usually undesirable,
	// because it makes bodies move as if they float.
	LinearDamping Q

	// Angular damping reduces the angular velocity. A value larger than 1 is
	// valid but grows sensitive to the time step.
	AngularDamping Q

	// Scale of the gravity on this body, non-dimensional.
	GravityScale Q

	// Sleep speed threshold, default 0.05 meters per second.
	SleepThreshold Q

	// Optional body name for debugging, up to 31 bytes.
	Name string

	// Application data attached to the body.
	UserData any

	// Set this to false if the body must never fall asleep.
	EnableSleep bool

	// Whether the body starts awake.
	IsAwake bool

	// Prevent the body from rotating. Useful for characters.
	FixedRotation bool

	// Treat the body as a high speed object that performs continuous
	// collision against dynamic and kinematic bodies, but not against other
	// bullets. Use sparingly: bullets solve no general dynamic-versus-dynamic
	// case and may interfere with joints.
	IsBullet bool

	// A disabled body does not move and does not collide.
	IsEnabled bool

	// Let the body bypass the rotational speed limit. Only for circular
	// bodies, like wheels.
	AllowFastRotation bool
	// contains filtered or unexported fields
}

BodyDef holds the data to construct a rigid body. It is a temporary bundle of creation parameters; shapes come after construction. Initialize it with DefaultBodyDef.

func DefaultBodyDef

func DefaultBodyDef() BodyDef

DefaultBodyDef returns the default body definition.

type BodyId

type BodyId struct {
	// contains filtered or unexported fields
}

BodyId identifies a body. Its zero value is null.

func CreateBody

func CreateBody(worldId WorldId, def *BodyDef) BodyId

CreateBody creates a rigid body from a definition. The definition must come from DefaultBodyDef and is not retained.

func LoadBodyId

func LoadBodyId(x uint64) BodyId

LoadBodyId unpacks a body id from a uint64.

func (BodyId) IsNull

func (id BodyId) IsNull() bool

IsNull reports whether the id references nothing.

func (BodyId) IsValid

func (id BodyId) IsValid() bool

IsValid reports whether the id references a live body.

func (BodyId) Mass

func (bodyId BodyId) Mass() Q

Mass returns the mass of the body, usually in kilograms.

func (BodyId) Position

func (bodyId BodyId) Position() Vec2

Position returns the world position of the body origin.

func (BodyId) Rotation

func (bodyId BodyId) Rotation() Rot

Rotation returns the world rotation of the body.

func (BodyId) ShapeCount

func (bodyId BodyId) ShapeCount() int

ShapeCount returns the number of shapes on the body.

type BodyType

type BodyType int

BodyType selects how the solver treats a body.

const (
	// StaticBody has zero mass and zero velocity. An application may move it
	// manually.
	StaticBody BodyType = 0

	// KinematicBody has zero mass. The application sets the velocity and the
	// solver moves it.
	KinematicBody BodyType = 1

	// DynamicBody has positive mass. Forces determine the velocity and the
	// solver moves it.
	DynamicBody BodyType = 2

	// BodyTypeCount is the number of body types.
	BodyTypeCount = 3
)

type Capsule

type Capsule struct {
	// Center1 is the local center of the first semicircle.
	Center1 Vec2

	// Center2 is the local center of the second semicircle.
	Center2 Vec2

	// Radius is the radius of both semicircles.
	Radius Q
}

Capsule is a solid capsule: two semicircles joined by a rectangle.

type CastOutput

type CastOutput struct {
	// Normal is the surface normal at the hit point.
	Normal Vec2

	// Point is the surface hit point.
	Point Vec2

	// Fraction is the part of the input translation at the collision.
	Fraction Q

	// Iterations is the number of iterations the cast used.
	Iterations int

	// Hit reports whether the cast hit.
	Hit bool
}

CastOutput is the output of a ray cast or of a shape cast. An initial overlap returns a zero fraction and a zero normal.

func RayCastCapsule

func RayCastCapsule(input *RayCastInput, shape *Capsule) CastOutput

RayCastCapsule casts a ray against a capsule in local space. An initial overlap reports a hit at the ray origin with a zero fraction.

func RayCastCircle

func RayCastCircle(input *RayCastInput, shape *Circle) CastOutput

RayCastCircle casts a ray against a circle in local space. An initial overlap reports a hit at the ray origin with a zero fraction.

func RayCastPolygon

func RayCastPolygon(input *RayCastInput, shape *Polygon) CastOutput

RayCastPolygon casts a ray against a convex polygon in local space. An initial overlap reports a hit at the ray origin with a zero fraction.

A rounded polygon needs the shape cast, which arrives with the distance stage, so this function accepts only a polygon with a zero radius.

func RayCastSegment

func RayCastSegment(input *RayCastInput, shape *Segment, oneSided bool) CastOutput

RayCastSegment casts a ray against a segment in local space. A one-sided segment reports a miss for a ray that arrives from the left.

type ChainId

type ChainId struct {
	// contains filtered or unexported fields
}

ChainId identifies a chain. Its zero value is null.

func LoadChainId

func LoadChainId(x uint64) ChainId

LoadChainId unpacks a chain id from a uint64.

func (ChainId) IsNull

func (id ChainId) IsNull() bool

IsNull reports whether the id references nothing.

type ChainSegment

type ChainSegment struct {
	// Ghost1 is the tail ghost vertex.
	Ghost1 Vec2

	// Segment is the colliding part.
	Segment Segment

	// Ghost2 is the head ghost vertex.
	Ghost2 Vec2

	// ChainId is the owning chain shape. It is internal bookkeeping.
	ChainId int
}

ChainSegment is a line segment with one-sided collision. It collides only on the right side. A chain shape generates several of them, in the order ghost1, point1, point2, ghost2.

type Circle

type Circle struct {
	Center Vec2
	Radius Q
}

Circle is a solid circle.

type Filter

type Filter struct {
	// The collision category bits of this shape. Normally one bit per
	// application object type.
	CategoryBits uint64

	// The categories that this shape accepts for collision.
	MaskBits uint64

	// Shapes in the same negative group never collide; in the same positive
	// group they always collide. Zero has no effect. A non-zero group wins
	// against the mask bits.
	GroupIndex int
}

Filter controls collision between shapes, and between queries and shapes.

func DefaultFilter

func DefaultFilter() Filter

DefaultFilter returns the default filter: category 1, every mask bit set, no group.

type Hull

type Hull struct {
	// Points holds the hull corners. Only the first Count entries are valid.
	Points [MaxPolygonVertices]Vec2

	// Count is the number of points.
	Count int
}

Hull is a convex hull. It feeds the polygon constructors. Build one with ComputeHull and do not modify it afterwards.

func ComputeHull

func ComputeHull(points []Vec2) Hull

ComputeHull returns the convex hull of a set of points. It welds points that are closer than four linear slops and it drops collinear points. It returns an empty hull on failure: fewer than three points, more than MaxPolygonVertices points, points all very close, or points all on a line.

type JointId

type JointId struct {
	// contains filtered or unexported fields
}

JointId identifies a joint. Its zero value is null.

func LoadJointId

func LoadJointId(x uint64) JointId

LoadJointId unpacks a joint id from a uint64.

func (JointId) IsNull

func (id JointId) IsNull() bool

IsNull reports whether the id references nothing.

type Manifold

type Manifold struct {
	// Normal is the unit normal in world space. It points from A to B.
	Normal Vec2

	// RollingImpulse is the angular impulse of the rolling resistance.
	RollingImpulse Q

	// Points holds the contact points. Two are possible in 2D.
	Points [2]ManifoldPoint

	// PointCount is zero, one or two.
	PointCount int
}

Manifold describes the contact points between two colliding shapes. The solver uses speculative collision, so a point may still be separated.

type ManifoldPoint

type ManifoldPoint struct {
	// Point is the contact point in world space. Use it for debugging only,
	// because it loses precision far from the origin.
	Point Vec2

	// AnchorA is the contact point relative to the origin of shape A, in
	// world space. Inside the solver it is relative to the center of mass.
	AnchorA Vec2

	// AnchorB is the contact point relative to the origin of shape B, in
	// world space. Inside the solver it is relative to the center of mass.
	AnchorB Vec2

	// Separation is negative when the shapes penetrate.
	Separation Q

	// NormalImpulse is the impulse along the manifold normal.
	NormalImpulse Q

	// TangentImpulse is the friction impulse.
	TangentImpulse Q

	// TotalNormalImpulse accumulates over the substeps and the restitution
	// pass. It tells a speculative point that acted from one that did not.
	TotalNormalImpulse Q

	// NormalVelocity is the relative normal velocity before the solve. It
	// feeds the hit events. A negative value means the shapes approach.
	NormalVelocity Q

	// Id identifies the contact point between the two shapes.
	Id uint16

	// Persisted reports whether the point existed in the previous step.
	Persisted bool
}

ManifoldPoint is one contact point of a contact manifold. The solver uses speculative collision, so a point may still be separated.

type MassData

type MassData struct {
	// Mass is the mass of the shape, usually in kilograms.
	Mass Q

	// Center is the centroid of the shape, relative to the shape origin.
	Center Vec2

	// RotationalInertia is measured about the local origin.
	RotationalInertia Q
}

MassData holds the mass properties of a shape.

func ComputeCapsuleMass

func ComputeCapsuleMass(shape *Capsule, density Q) MassData

ComputeCapsuleMass returns the mass properties of a capsule.

func ComputeCircleMass

func ComputeCircleMass(shape *Circle, density Q) MassData

ComputeCircleMass returns the mass properties of a circle.

func ComputePolygonMass

func ComputePolygonMass(shape *Polygon, density Q) MassData

ComputePolygonMass returns the mass properties of a convex polygon. It approximates a rounded polygon by pushing the vertices outward.

type Mat22

type Mat22 struct {
	Cx, Cy Vec2
}

Mat22 is a 2-by-2 matrix, stored as its columns.

func GetInverse22

func GetInverse22(m Mat22) Mat22

GetInverse22 returns the inverse of m. A singular matrix returns the zero matrix.

Each entry divides by the determinant, because a fixed-point reciprocal loses the precision that the division keeps. See DIVERGENCES.md.

func Mat22Zero

func Mat22Zero() Mat22

Mat22Zero returns the zero matrix.

type Plane

type Plane struct {
	Normal Vec2
	Offset Q
}

Plane separates space. The separation of a point is dot(normal, point) - offset.

type Polygon

type Polygon struct {
	// Vertices holds the corners. Only the first Count entries are valid.
	Vertices [MaxPolygonVertices]Vec2

	// Normals holds the outward normal of each side.
	Normals [MaxPolygonVertices]Vec2

	// Centroid is the area centroid of the polygon.
	Centroid Vec2

	// Radius is the external radius of a rounded polygon.
	Radius Q

	// Count is the number of vertices.
	Count int
}

Polygon is a solid convex polygon. The interior lies to the left of every edge. Build one with MakePolygon or MakeBox; never fill the fields by hand.

func MakeBox

func MakeBox(halfWidth, halfHeight Q) Polygon

MakeBox returns a rectangle polygon of the given half-extents, without a hull. It panics on a half-extent that is not positive.

func MakeOffsetBox

func MakeOffsetBox(halfWidth, halfHeight Q, center Vec2, rotation Rot) Polygon

MakeOffsetBox returns a rectangle polygon placed at a center and a rotation, without a hull.

func MakeOffsetPolygon

func MakeOffsetPolygon(hull *Hull, position Vec2, rotation Rot) Polygon

MakeOffsetPolygon returns a convex polygon built from a hull and placed at a position and a rotation.

func MakeOffsetRoundedBox

func MakeOffsetRoundedBox(halfWidth, halfHeight Q, center Vec2, rotation Rot, radius Q) Polygon

MakeOffsetRoundedBox returns a rectangle polygon with rounded corners, placed at a center and a rotation, without a hull.

func MakeOffsetRoundedPolygon

func MakeOffsetRoundedPolygon(hull *Hull, position Vec2, rotation Rot, radius Q) Polygon

MakeOffsetRoundedPolygon returns a convex polygon built from a hull, placed at a position and a rotation, with rounded corners of the given radius.

func MakePolygon

func MakePolygon(hull *Hull, radius Q) Polygon

MakePolygon returns a convex polygon built from a hull. The radius rounds the corners. It panics on a hull that ValidateHull rejects.

func MakeRoundedBox

func MakeRoundedBox(halfWidth, halfHeight, radius Q) Polygon

MakeRoundedBox returns a rectangle polygon with rounded corners, without a hull.

func MakeSquare

func MakeSquare(halfWidth Q) Polygon

MakeSquare returns a square polygon of the given half-width, without a hull.

func TransformPolygon

func TransformPolygon(transform Transform, polygon *Polygon) Polygon

TransformPolygon returns the polygon moved by a transform. It moves a shape from one body to another.

type Q

type Q = fixed.Q

Q is a signed Q32.32 fixed-point number.

func AABBMargin

func AABBMargin() Q

AABBMargin fattens the bounds in the dynamic tree, in meters. A proxy that moves less than the margin triggers no tree adjustment.

Changing it has a significant effect on performance.

func ComputeAngularVelocity

func ComputeAngularVelocity(q1, q2 Rot, invH Q) Q

ComputeAngularVelocity returns the angular velocity, in turns per second, that rotates q1 into q2 over one step. invH is the inverse time step.

func Cross

func Cross(a, b Vec2) Q

Cross returns the 2D cross product, which is a scalar.

func JointConstraintDampingRatio

func JointConstraintDampingRatio() Q

JointConstraintDampingRatio is the default damping of a joint constraint.

func JointConstraintHertz

func JointConstraintHertz() Q

JointConstraintHertz is the default stiffness of a joint constraint.

func LinearSlop

func LinearSlop() Q

LinearSlop is the collision and constraint tolerance in meters. It is numerically significant and visually insignificant.

Changing it has a significant effect on stability.

func MaxRotation

func MaxRotation() Q

MaxRotation is the largest rotation of a body in one time step, in turns. The limit prevents numerical problems.

Raising it to 0.25 turns or more breaks continuous collision.

func Pi

func Pi() Q

Pi is the ratio of a circumference to its diameter. An angle is a turn in this package; Pi serves the formulas that the reference writes in radians.

func PlaneSeparation

func PlaneSeparation(plane Plane, point Vec2) Q

PlaneSeparation returns the signed distance of a point from a plane.

func RelativeAngle

func RelativeAngle(b, a Rot) Q

RelativeAngle returns the angle of b relative to a, in turns.

func RotGetAngle

func RotGetAngle(q Rot) Q

RotGetAngle returns the angle of q in turns, in the range [-0.5, 0.5].

func SpeculativeDistance

func SpeculativeDistance() Q

SpeculativeDistance is the range of limited speculative collision, in meters. It reduces jitter.

Changing it has a significant effect on performance and stability.

func SpringDamper

func SpringDamper(hertz, dampingRatio, position, velocity, timeStep Q) Q

SpringDamper simulates a one-dimensional mass-spring-damper and returns the new velocity. The caller then computes the new position:

position += timeStep * newVelocity

It drives towards a zero position. Implicit integration makes the solution stable and free of transcendental functions.

func TimeToSleep

func TimeToSleep() Q

TimeToSleep is how long a body must stay still before it sleeps, in seconds.

func UnwindAngle

func UnwindAngle(t Q) Q

UnwindAngle reduces an angle in turns to the range [-0.5, 0.5]. One turn is one unit here, so the reduction is exact and needs no remainder of pi.

type QueryFilter

type QueryFilter struct {
	// The collision category bits of this query. Normally one bit.
	CategoryBits uint64

	// The shape categories that this query accepts for collision.
	MaskBits uint64
}

QueryFilter controls collision between a query and the shapes it visits.

func DefaultQueryFilter

func DefaultQueryFilter() QueryFilter

DefaultQueryFilter returns the default query filter: category 1, every mask bit set.

type RayCastInput

type RayCastInput struct {
	// Origin is the start point of the ray.
	Origin Vec2

	// Translation is the displacement of the ray.
	Translation Vec2

	// MaxFraction limits the translation to consider. It is usually one.
	MaxFraction Q
}

RayCastInput is the input of a ray cast in the local frame of a shape.

type Rot

type Rot = fixed.Rot

Rot is a 2D rotation, stored as a sine and cosine pair.

func ComputeRotationBetweenUnitVectors

func ComputeRotationBetweenUnitVectors(v1, v2 Vec2) Rot

ComputeRotationBetweenUnitVectors returns the rotation that carries the unit vector v1 onto the unit vector v2. It panics when either vector is not a unit vector, because the result would be a rotation of the wrong scale.

func IntegrateRotation

func IntegrateRotation(q1 Rot, deltaAngle Q) Rot

IntegrateRotation advances q1 by the angular displacement deltaAngle, in turns, and renormalizes. The first-order step below needs radians, so the displacement scales by one turn.

func InvMulRot

func InvMulRot(q, r Rot) Rot

InvMulRot returns the rotation transpose(q) * r.

[ qc qs] * [rc -rs] = [qc*rc+qs*rs -qc*rs+qs*rc]
[-qs qc]   [rs  rc]   [-qs*rc+qc*rs qs*rs+qc*rc]
s(q - r) = qc * rs - qs * rc
c(q - r) = qc * rc + qs * rs

func MakeRot

func MakeRot(t Q) Rot

MakeRot returns the rotation by the angle t, in turns.

func MulRot

func MulRot(q, r Rot) Rot

MulRot returns the rotation q * r.

[qc -qs] * [rc -rs] = [qc*rc-qs*rs -qc*rs-qs*rc]
[qs  qc]   [rs  rc]   [qs*rc+qc*rs -qs*rs+qc*rc]
s(q + r) = qs * rc + qc * rs
c(q + r) = qc * rc - qs * rs

func NLerp

func NLerp(q1, q2 Rot, t Q) Rot

NLerp interpolates between q1 and q2 by t and renormalizes.

func NormalizeRot

func NormalizeRot(q Rot) Rot

NormalizeRot rescales q to unit length.

A zero q returns a zero rotation, as the reference does. The zero rotation is invalid, so IsValidRotation reports the bad state instead of hiding it behind the identity.

func RotIdentity

func RotIdentity() Rot

RotIdentity returns the rotation by zero turns.

type Segment

type Segment struct {
	Point1 Vec2
	Point2 Vec2
}

Segment is a line segment with two-sided collision.

type ShapeCastInput

type ShapeCastInput struct {
	Proxy       ShapeProxy
	Translation Vec2

	// MaxFraction limits the translation to consider. It is usually one.
	MaxFraction Q

	// CanEncroach lets a cast that starts in contact advance. It applies
	// only when the radius is greater than zero.
	CanEncroach bool
}

ShapeCastInput is the input of a shape cast in generic form.

type ShapeDef

type ShapeDef struct {
	// Application data attached to the shape.
	UserData any

	// The surface material of this shape.
	Material SurfaceMaterial

	// The density, usually in kg/m^2. It stays out of the material because
	// it describes the interior, which may be hollow.
	Density Q

	// Collision filtering data.
	Filter Filter

	// A sensor generates overlap events and never a collision response.
	// Warning: sensors are not ported yet. Creating a shape with IsSensor set
	// panics.
	IsSensor bool

	// Enable sensor events for this shape. False by default, even for
	// sensors.
	EnableSensorEvents bool

	// Enable contact events. Only for kinematic and dynamic bodies. Ignored
	// for sensors.
	EnableContactEvents bool

	// Enable hit events. Only for kinematic and dynamic bodies. Ignored for
	// sensors.
	EnableHitEvents bool

	// Enable pre-solve contact events. Only for dynamic bodies. Ignored for
	// sensors.
	EnablePreSolveEvents bool

	// A new shape scans the environment for collision on the next step. This
	// flag skips the scan on a static body, where the scan is the dominant
	// creation cost. Dynamic and kinematic shapes ignore the flag.
	InvokeContactCreation bool

	// Update the mass of the body when this shape is created. Default true.
	UpdateBodyMass bool
	// contains filtered or unexported fields
}

ShapeDef holds the data to create a shape. It is a temporary bundle of creation parameters; one definition may create many shapes. Initialize it with DefaultShapeDef.

func DefaultShapeDef

func DefaultShapeDef() ShapeDef

DefaultShapeDef returns the default shape definition.

type ShapeId

type ShapeId struct {
	// contains filtered or unexported fields
}

ShapeId identifies a shape. Its zero value is null.

func CreateCapsuleShape

func CreateCapsuleShape(bodyId BodyId, def *ShapeDef, capsule *Capsule) ShapeId

CreateCapsuleShape creates a capsule shape on a body. A capsule shorter than the linear slop becomes a circle at its midpoint.

func CreateCircleShape

func CreateCircleShape(bodyId BodyId, def *ShapeDef, circle *Circle) ShapeId

CreateCircleShape creates a circle shape on a body. The definition must come from DefaultShapeDef and is not retained.

func CreatePolygonShape

func CreatePolygonShape(bodyId BodyId, def *ShapeDef, polygon *Polygon) ShapeId

CreatePolygonShape creates a polygon shape on a body. Build the polygon with MakePolygon or MakeBox.

func CreateSegmentShape

func CreateSegmentShape(bodyId BodyId, def *ShapeDef, segment *Segment) ShapeId

CreateSegmentShape creates a segment shape on a body. It panics on a segment shorter than the linear slop.

func LoadShapeId

func LoadShapeId(x uint64) ShapeId

LoadShapeId unpacks a shape id from a uint64.

func (ShapeId) IsNull

func (id ShapeId) IsNull() bool

IsNull reports whether the id references nothing.

func (ShapeId) IsValid

func (id ShapeId) IsValid() bool

IsValid reports whether the id references a live shape.

type ShapeProxy

type ShapeProxy struct {
	// Points holds the cloud. Only the first Count entries are valid.
	Points [MaxPolygonVertices]Vec2

	// Count is the number of points. It is greater than zero.
	Count int

	// Radius is the external radius of the cloud. It may be zero.
	Radius Q
}

ShapeProxy is a point cloud with an external radius. It stands for any shape in the distance and cast routines.

type ShapeType

type ShapeType int

ShapeType identifies the geometry of a shape.

const (
	// CircleShape is a circle with an offset.
	CircleShape ShapeType = iota

	// CapsuleShape is an extruded circle.
	CapsuleShape

	// SegmentShape is a line segment.
	SegmentShape

	// PolygonShape is a convex polygon.
	PolygonShape

	// ChainSegmentShape is a line segment owned by a chain shape.
	ChainSegmentShape

	// ShapeTypeCount is the number of shape types.
	ShapeTypeCount
)

type SurfaceMaterial

type SurfaceMaterial struct {
	// The Coulomb friction coefficient, usually in the range [0, 1].
	Friction Q

	// The coefficient of restitution, usually in the range [0, 1].
	Restitution Q

	// The rolling resistance, usually in the range [0, 1].
	RollingResistance Q

	// The tangent speed, for conveyor belts.
	TangentSpeed Q

	// Application material identifier, returned with query results. The
	// world does not use it.
	UserMaterialId int

	// Custom debug draw color.
	CustomColor uint32
}

SurfaceMaterial holds the surface properties of a shape.

func DefaultSurfaceMaterial

func DefaultSurfaceMaterial() SurfaceMaterial

DefaultSurfaceMaterial returns the default material: friction 0.6.

type Transform

type Transform struct {
	P Vec2
	Q Rot
}

Transform is a 2D rigid transform.

func InvMulTransforms

func InvMulTransforms(a, b Transform) Transform

InvMulTransforms returns the transform that converts a point local to frame b into a point local to frame a.

v2 = inv(a.q) * (b.q * v1 + b.p - a.p)
   = inv(a.q) * b.q * v1 + inv(a.q) * (b.p - a.p)

func MulTransforms

func MulTransforms(a, b Transform) Transform

MulTransforms composes two transforms. Applied to a point local to frame b, the result converts it to a point local to frame a, then to a point in the world frame.

v2 = a.q.Rot(b.q.Rot(v1) + b.p) + a.p
   = (a.q * b.q).Rot(v1) + a.q.Rot(b.p) + a.p

func TransformIdentity

func TransformIdentity() Transform

TransformIdentity returns the transform that moves and rotates nothing.

type Vec2

type Vec2 = fixed.Vec2

Vec2 is a 2D vector. It represents a point or a free vector.

func AABBCenter

func AABBCenter(a AABB) Vec2

AABBCenter returns the center of a.

func AABBExtents

func AABBExtents(a AABB) Vec2

AABBExtents returns the half-widths of a.

func Abs

func Abs(a Vec2) Vec2

Abs returns the component-wise absolute value of a.

func Clamp

func Clamp(v, a, b Vec2) Vec2

Clamp returns v limited component-wise to the box [a, b].

func CrossSV

func CrossSV(s Q, v Vec2) Vec2

CrossSV returns the cross product of a scalar and a vector.

func CrossVS

func CrossVS(v Vec2, s Q) Vec2

CrossVS returns the cross product of a vector and a scalar.

func InvRotateVector

func InvRotateVector(q Rot, v Vec2) Vec2

InvRotateVector rotates v by the inverse of q.

func InvTransformPoint

func InvTransformPoint(t Transform, p Vec2) Vec2

InvTransformPoint carries the point p from the parent frame into the frame of t, for example from world space into local space.

func LeftPerp

func LeftPerp(v Vec2) Vec2

LeftPerp returns the left-pointing perpendicular of v. It equals CrossSV(one, v).

func Lerp

func Lerp(a, b Vec2, t Q) Vec2

Lerp interpolates between a and b by t.

It weighs both ends, unlike the Lerp method of the fixed-point module, which adds a scaled difference. The two round differently.

func Max

func Max(a, b Vec2) Vec2

Max returns the component-wise maximum of a and b.

func Min

func Min(a, b Vec2) Vec2

Min returns the component-wise minimum of a and b.

func Mul

func Mul(a, b Vec2) Vec2

Mul returns the component-wise product of a and b.

func MulAdd

func MulAdd(a Vec2, s Q, b Vec2) Vec2

MulAdd returns a + s * b.

func MulMV

func MulMV(m Mat22, v Vec2) Vec2

MulMV returns the product of the matrix m and the vector v.

func MulSub

func MulSub(a Vec2, s Q, b Vec2) Vec2

MulSub returns a - s * b.

func Neg

func Neg(a Vec2) Vec2

Neg returns the negation of a.

func RightPerp

func RightPerp(v Vec2) Vec2

RightPerp returns the right-pointing perpendicular of v. It equals CrossVS(v, one).

func RotGetXAxis

func RotGetXAxis(q Rot) Vec2

RotGetXAxis returns the x axis of q.

func RotGetYAxis

func RotGetYAxis(q Rot) Vec2

RotGetYAxis returns the y axis of q.

func RotateVector

func RotateVector(q Rot, v Vec2) Vec2

RotateVector rotates v by q.

func Solve22

func Solve22(m Mat22, b Vec2) Vec2

Solve22 solves m * x = b for the column vector b. It is cheaper than the inverse for a one-shot case. A singular matrix returns the zero vector.

func TransformPoint

func TransformPoint(t Transform, p Vec2) Vec2

TransformPoint carries the point p from the frame of t into the parent frame, for example from local space into world space.

func Vec2Zero

func Vec2Zero() Vec2

Vec2Zero returns the zero vector.

type Version

type Version struct {
	// Major counts significant changes.
	Major int

	// Minor counts incremental changes.
	Minor int

	// Revision counts bug fixes.
	Revision int
}

Version reports a three-part release number.

func ReferenceVersion

func ReferenceVersion() Version

ReferenceVersion returns the Box2D release that this package ports. The module has its own version; this one identifies the reference source.

type WorldDef

type WorldDef struct {
	// Gravity vector. The world has no up vector.
	Gravity Vec2

	// Restitution speed threshold, usually in meters per second. Collisions
	// above this speed have restitution applied, so they bounce.
	RestitutionThreshold Q

	// Threshold speed for hit events, usually in meters per second.
	HitEventThreshold Q

	// Contact stiffness in cycles per second. Increasing this increases the
	// speed of overlap recovery, but can introduce jitter.
	ContactHertz Q

	// Contact bounciness, non-dimensional. Decreasing this speeds up overlap
	// recovery, with a more energetic resolution as the trade-off.
	ContactDampingRatio Q

	// A cap on the overlap resolution speed, usually in meters per second.
	// The hertz and the damping ratio set the speed itself.
	MaxContactPushSpeed Q

	// Maximum linear speed, usually in meters per second.
	MaximumLinearSpeed Q

	// Enable sleeping to improve performance.
	EnableSleep bool

	// Enable continuous collision.
	EnableContinuous bool

	// Application data attached to the world.
	UserData any
	// contains filtered or unexported fields
}

WorldDef configures the creation of a world. Initialize it with DefaultWorldDef.

func DefaultWorldDef

func DefaultWorldDef() WorldDef

DefaultWorldDef returns the default world definition.

type WorldId

type WorldId struct {
	// contains filtered or unexported fields
}

WorldId identifies a world. Its zero value is null.

func CreateWorld

func CreateWorld(def *WorldDef) WorldId

CreateWorld creates a world from a definition. The definition must come from DefaultWorldDef and is not retained. It returns the null id when every slot of the registry is in use.

func LoadWorldId

func LoadWorldId(x uint32) WorldId

LoadWorldId unpacks a world id from a uint32.

func (WorldId) Gravity

func (id WorldId) Gravity() Vec2

Gravity returns the gravity vector of the world.

func (WorldId) IsNull

func (id WorldId) IsNull() bool

IsNull reports whether the id references nothing.

func (WorldId) IsValid

func (id WorldId) IsValid() bool

IsValid reports whether the id references a live world. It lets an application hold ids safely across destruction.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL