Expand description
boxdd: Safe, ergonomic Rust bindings for Box2D (v3 C API)
Highlights
- Thin safe layer on top of the official Box2D v3 C API.
- Modular API: world, bodies, shapes, joints, queries, events, debug draw.
- Ergonomics: builder patterns, world-space helpers, optional
mintintegration. - Three usage styles:
- Owned handles:
OwnedBody/OwnedShape/OwnedJoint/OwnedChain(Drop destroys; easy to store). - Scoped handles:
Body<'_>/Shape<'_>/Joint<'_>/Chain<'_>(dropping only releases the world borrow). - ID-style: raw ids (
BodyId/ShapeId/JointId/ChainId) for maximum flexibility.
- Owned handles:
- Safe handle methods validate ids and panic on invalid ids (prevents UB if an id becomes stale).
For recoverable failures (invalid ids / calling during Box2D callbacks), use
try_*APIs returningApiResult<T>. - Threading:
Worldand owned handles are!Send/!Sync. Run physics on one thread; in async runtimes preferspawn_local/LocalSet, or create the world inside a dedicated physics thread and communicate via channels.
Quickstart (owned handles)
use boxdd::{World, WorldDef, BodyBuilder, ShapeDef, shapes, Vec2};
let def = WorldDef::builder().gravity(Vec2::new(0.0, -9.8)).build();
let mut world = World::new(def).unwrap();
let body = world.create_body_owned(BodyBuilder::new().position([0.0, 2.0]).build());
let sdef = ShapeDef::builder().density(1.0).build();
let poly = shapes::box_polygon(0.5, 0.5);
let _shape = world.create_polygon_shape_for_owned(body.id(), &sdef, &poly);
world.step(1.0/60.0, 4);Quickstart (scoped handles)
use boxdd::{World, WorldDef, BodyBuilder, ShapeDef, shapes, Vec2};
let def = WorldDef::builder().gravity(Vec2::new(0.0, -9.8)).build();
let mut world = World::new(def).unwrap();
{
// Limit the borrow of `world` by scoping the body handle.
let mut body = world.create_body(BodyBuilder::new().position([0.0, 2.0]).build());
let sdef = ShapeDef::builder().density(1.0).build();
let poly = shapes::box_polygon(0.5, 0.5);
let _shape = body.create_polygon_shape(&sdef, &poly);
}
world.step(1.0/60.0, 4);Quickstart (ID-style)
use boxdd::{World, WorldDef, BodyBuilder, ShapeDef, shapes, Vec2};
let def = WorldDef::builder().gravity(Vec2::new(0.0, -9.8)).build();
let mut world = World::new(def).unwrap();
let body_id = world.create_body_id(BodyBuilder::new().position([0.0, 2.0]).build());
let sdef = ShapeDef::builder().density(1.0).build();
let poly = shapes::box_polygon(0.5, 0.5);
let _shape_id = world.create_polygon_shape_for(body_id, &sdef, &poly);
world.step(1.0/60.0, 4);Math interop (optional features)
Vec2always accepts[f32; 2]and(f32, f32)anywhereInto<Vec2>is used.- With
mint,cgmath,nalgebra, orglamenabled,Vec2also accepts those crates’ 2D vector/point types viaFrom/Into. - Returned vectors can be converted back using
Fromto the corresponding math types.
Modules
world,body,shapes,joints,query,events,debug_draw,prelude. Importboxdd::prelude::*for the most common types.
Queries (AABB + Ray Cast)
use boxdd::{World, WorldDef, BodyBuilder, ShapeDef, shapes, Vec2, Aabb, QueryFilter};
let mut world = World::new(WorldDef::builder().gravity([0.0,-9.8]).build()).unwrap();
let b = world.create_body_id(BodyBuilder::new().position([0.0, 2.0]).build());
let sdef = ShapeDef::builder().density(1.0).build();
world.create_polygon_shape_for(b, &sdef, &shapes::box_polygon(0.5, 0.5));
// AABB overlap
let hits = world.overlap_aabb(Aabb::from_center_half_extents([0.0, 1.0], [1.0, 1.5]), QueryFilter::default());
assert!(!hits.is_empty());
// Ray (closest)
let r = world.cast_ray_closest(Vec2::new(0.0, 5.0), Vec2::new(0.0, -10.0), QueryFilter::default());
if r.hit { let _ = (r.point, r.normal, r.fraction); }Feature Flags
serialize: scene snapshot helpers (save/apply world config; build/restore minimal full-scene snapshot).pkg-config: allow linking against a systembox2dvia pkg-config.mint: lightweight math interop types (mint::Vector2,mint::Point2, and 2D affine matrices forTransform).cgmath/nalgebra/glam: conversions with their 2D math types.bytemuck:Pod/Zeroablefor core math types (Vec2,Rot,Transform,Aabb) for zero-copy interop.
Events
- Three access styles:
- By value:
world.contact_events()/sensor_events()/body_events()/joint_events()return owned data for storage or cross‑frame use. - Zero‑copy views:
with_*_events_view(...)iterate without allocations (borrows internal buffers). - Raw slices:
unsafe { with_*_events(...) }expose FFI slices (borrows internal buffers).
- By value:
Example (zero‑copy views)
use boxdd::prelude::*;
let mut world = World::new(WorldDef::default()).unwrap();
world.with_contact_events_view(|begin, end, hit| {
let _ = (begin.count(), end.count(), hit.count());
});
world.with_sensor_events_view(|beg, end| { let _ = (beg.count(), end.count()); });
world.with_body_events_view(|moves| { for m in moves { let _ = (m.body_id(), m.fell_asleep()); } });
world.with_joint_events_view(|j| { let _ = j.count(); });Re-exports§
pub use body::OwnedBody;pub use body::Body;pub use body::BodyBuilder;pub use body::BodyDef;pub use body::BodyType;pub use core::math::Rot;pub use core::math::Transform;pub use debug_draw::DebugDraw;pub use debug_draw::DebugDrawCmd;pub use debug_draw::DebugDrawOptions;pub use error::ApiError;pub use error::ApiResult;pub use events::BodyMoveEvent;pub use events::ContactBeginTouchEvent;pub use events::ContactEndTouchEvent;pub use events::ContactEvents;pub use events::ContactHitEvent;pub use events::JointEvent;pub use events::SensorBeginTouchEvent;pub use events::SensorEndTouchEvent;pub use events::SensorEvents;pub use filter::Filter;pub use joints::DistanceJointBuilder;pub use joints::DistanceJointDef;pub use joints::FilterJointBuilder;pub use joints::FilterJointDef;pub use joints::Joint;pub use joints::JointBase;pub use joints::JointBaseBuilder;pub use joints::MotorJointBuilder;pub use joints::MotorJointDef;pub use joints::PrismaticJointBuilder;pub use joints::PrismaticJointDef;pub use joints::RevoluteJointBuilder;pub use joints::RevoluteJointDef;pub use joints::WeldJointBuilder;pub use joints::WeldJointDef;pub use joints::WheelJointBuilder;pub use joints::WheelJointDef;pub use query::Aabb;pub use query::QueryFilter;pub use query::RayResult;pub use shapes::chain::Chain;pub use shapes::chain::ChainDef;pub use shapes::chain::ChainDefBuilder;pub use shapes::chain::OwnedChain;pub use shapes::OwnedShape;pub use shapes::Shape;pub use shapes::ShapeDef;pub use shapes::ShapeDefBuilder;pub use shapes::SurfaceMaterial;pub use types::Vec2;pub use world::CallbackWorld;pub use world::OutstandingOwnedHandles;pub use world::OwnedHandleCounts;pub use world::World;pub use world::WorldBuilder;pub use world::WorldDef;pub use world::WorldHandle;
Modules§
- body
- core
- debug_
draw - Debug Draw bridge to Box2D v3 callbacks.
- error
- Fallible error types for
try_*APIs. - events
- Event snapshots and zero-copy visitors.
- filter
- joints
- Joint builders and creation helpers (modularized).
- prelude
- query
- Broad-phase queries and casting helpers.
- shapes
- Shapes API
- tuning
- Tuning Notes and Upstream Constants
- types
- world
- world_
extras - Optional world extensions that are not core to the safe API surface.