chipmunk2d_physics_ffi 1.0.3
chipmunk2d_physics_ffi: ^1.0.3 copied to clipboard
Flutter FFI plugin for Chipmunk2D physics engine - a lightweight 2D physics library
chipmunk2d_physics_ffi #
A comprehensive Dart FFI binding for Chipmunk2D physics engine version 7.0.3. This package provides a complete, idiomatic Dart API for 2D physics simulation in Flutter and Dart applications.
Demo #
Features #
- Complete API Coverage: 1-1 API compliance with Chipmunk2D 7.0.3
- Idiomatic Dart API: Clean, object-oriented wrapper around Chipmunk's C API with type-safe enums and helper methods
- Full Feature Set:
- Dynamic, kinematic, and static bodies
- Circle, box, segment, and polygon shapes
- 10 joint types (Pin, Slide, Pivot, Groove, Springs, Rotary, Ratchet, Gear, Motor)
- Collision detection and filtering with helper methods
- Spatial queries (point, segment, bounding box) with typed result classes
- Sleeping and activation system
- Force and impulse application
- Moment of inertia and area calculations
- Cross-Platform: Supports iOS, Android, macOS, Linux, Windows, and Web
- Performance: Direct FFI bindings with minimal overhead
Installation #
Add this package to your pubspec.yaml:
dependencies:
chipmunk2d_physics_ffi: ^1.0.2
Then run:
flutter pub get
Quick Start #
import 'package:chipmunk2d_physics_ffi/chipmunk2d_physics_ffi.dart';
void main() async {
// On web, initialize Chipmunk2D before use (no-op on native platforms)
WidgetsFlutterBinding.ensureInitialized();
await initializeChipmunk();
// Create a physics space
final space = Space();
space.gravity = Vector(0, -100); // Gravity pointing down
// Create a dynamic body
final body = Body.dynamic(1.0, 1.0); // mass, moment
body.position = Vector(0, 100);
// Create a circle shape
final shape = CircleShape(body, 10.0); // radius
shape.friction = 0.7;
shape.elasticity = 0.5;
// Add to space
space.addBody(body);
space.addShape(shape);
// Create a static ground
final ground = space.staticBody;
final groundShape = BoxShape(ground, 1000, 20);
space.addShape(groundShape);
// Simulate
for (var i = 0; i < 60; i++) {
space.step(1.0 / 60.0); // 60 FPS
print('Body position: ${body.position}');
}
// Cleanup
shape.dispose();
body.dispose();
space.dispose();
}
Core Concepts #
Space #
The Space is the simulation container. It manages all bodies, shapes, and
constraints, and steps the simulation forward in time.
final space = Space();
space.gravity = Vector(0, -100);
space.iterations = 10; // Solver iterations
space.damping = 0.9; // Global damping
space.step(1.0 / 60.0); // Step simulation
Body #
A Body represents a rigid body in the simulation. Bodies can be:
- Dynamic: Affected by forces, gravity, and collisions
- Kinematic: User-controlled, not affected by forces
- Static: Immovable, used for ground/walls
// Dynamic body
final body = Body.dynamic(1.0, 1.0); // mass, moment
body.position = Vector(0, 0);
body.velocity = Vector(10, 0);
body.angle = 0.5; // radians
// Apply forces
body.applyForceAtWorldPoint(Vector(0, -100), body.position);
body.applyImpulseAtWorldPoint(Vector(10, 0), body.position);
// Coordinate conversion
final worldPoint = body.localToWorld(Vector(5, 0));
final localPoint = body.worldToLocal(worldPoint);
Shape #
Shapes define the collision geometry of bodies. Supported shape types:
- CircleShape: Perfect for balls, wheels, etc.
- BoxShape: Rectangles with optional rounded corners
- SegmentShape: Line segments for walls, platforms
- PolyShape: Convex polygons for complex shapes
// Circle
final circle = CircleShape(body, 10.0, offset: Vector(0, 0));
circle.friction = 0.7;
circle.elasticity = 0.5;
circle.sensor = false; // Set to true for trigger zones
// Box
final box = BoxShape(body, 50, 30, radius: 2.0); // width, height, corner radius
// Segment (line)
final segment = SegmentShape(body, Vector(0, 0), Vector(100, 0), 2.0);
// Polygon
final vertices = [
Vector(0, 0),
Vector(50, 0),
Vector(50, 30),
Vector(0, 30),
];
final poly = PolyShape(body, vertices, radius: 1.0);
Constraints (Joints) #
Constraints connect two bodies together. Available joint types:
- PinJoint: Fixed distance between two anchor points
- SlideJoint: Distance constrained to min/max range
- PivotJoint: Bodies pivot around a common point
- GrooveJoint: Pivot constrained to a groove
- DampedSpring: Spring with damping
- DampedRotarySpring: Rotational spring
- RotaryLimitJoint: Limits angular rotation
- RatchetJoint: One-way rotational constraint
- GearJoint: Synchronized rotation
- SimpleMotor: Constant velocity rotation
// Pin joint
final joint = PinJoint(bodyA, bodyB, anchorA, anchorB);
joint.distance = 50.0;
space.addConstraint(joint);
// Spring
final spring = DampedSpring(
bodyA, bodyB,
anchorA, anchorB,
100.0, // rest length
1000.0, // stiffness
10.0, // damping
);
space.addConstraint(spring);
API Overview #
Body API #
// Properties
body.position // Vector
body.velocity // Vector
body.angle // double (radians)
body.angularVelocity // double (radians/sec)
body.mass // double
body.moment // double
body.centerOfGravity // Vector
body.force // Vector
body.torque // double
body.rotation // Vector
body.type // BodyType (BodyType.dynamic, BodyType.kinematic, BodyType.static)
body.isSleeping // bool
// Methods
body.activate()
body.sleep()
body.localToWorld(Vector)
body.worldToLocal(Vector)
body.applyForceAtWorldPoint(Vector force, Vector point)
body.applyImpulseAtWorldPoint(Vector impulse, Vector point)
body.getVelocityAtWorldPoint(Vector point)
Shape API #
// Properties
shape.friction // double
shape.elasticity // double
shape.filter // ShapeFilter
shape.mass // double
shape.density // double
shape.moment // double
shape.area // double
shape.centerOfGravity // Vector
shape.boundingBox // BoundingBox
shape.sensor // bool
shape.surfaceVelocity // Vector
shape.collisionType // int
shape.body // Body?
// Collision Filtering
final filter = ShapeFilter.all(); // Collide with everything (default)
final filter = ShapeFilter.none(); // Collide with nothing
final filter = ShapeFilter.category(0x1); // Only collide with category 1
final filter = ShapeFilter.excludeCategory(0x2); // Collide with all except category 2
final filter = ShapeFilter.group(1); // Group that doesn't collide with itself
// CircleShape specific
circle.offset // Vector
circle.radius // double
// SegmentShape specific
segment.endpointA // Vector
segment.endpointB // Vector
segment.normal // Vector
segment.radius // double
segment.setNeighbors(Vector prev, Vector next)
// PolyShape specific
poly.vertexCount // int
poly.getVertex(int) // Vector
poly.radius // double
Space API #
// Properties
space.gravity // Vector
space.iterations // int
space.damping // double
space.idleSpeedThreshold // double
space.sleepTimeThreshold // double
space.collisionSlop // double
space.collisionBias // double
space.collisionPersistence // int
space.currentTimeStep // double
space.isLocked // bool
space.staticBody // Body
// Methods
space.addBody(Body)
space.removeBody(Body)
space.addShape(Shape)
space.removeShape(Shape)
space.addConstraint(Constraint)
space.removeConstraint(Constraint)
space.containsBody(Body) // bool
space.containsShape(Shape) // bool
space.containsConstraint(Constraint) // bool
space.step(double dt)
space.reindexStatic()
space.reindexShape(Shape)
space.reindexShapesForBody(Body)
Query Information #
The library provides Dart classes for query results:
// Point query information
final info = PointQueryInfo(
point: Vector(10, 20),
distance: 5.0,
gradient: Vector(1, 0),
shape: shape, // optional
);
// Segment query information
final segInfo = SegmentQueryInfo(
point: Vector(15, 25),
normal: Vector(0, 1),
alpha: 0.5,
shape: shape, // optional
);
Utility Functions #
Moment Calculations #
import 'package:chipmunk2d_physics_ffi/chipmunk2d_physics_ffi.dart';
// Calculate moment of inertia
final moment = momentForCircle(1.0, 0.0, 10.0, Vector.zero);
final boxMoment = momentForBox(1.0, 50.0, 30.0);
final polyMoment = momentForPoly(1.0, vertices, Vector.zero, 0.0);
// Calculate areas
final area = areaForCircle(0.0, 10.0);
final segmentArea = areaForSegment(Vector(0, 0), Vector(100, 0), 2.0);
// Calculate centroid
final centroid = centroidForPoly(vertices);
// Convex hull
final hull = convexHull(points, tolerance: 0.0);
Bounding Box #
final bb = BoundingBox(
left: -10,
bottom: -10,
right: 10,
top: 10,
);
// Or create from extents
final bb2 = BoundingBox.forExtents(Vector(0, 0), 10, 10);
final bb3 = BoundingBox.forCircle(Vector(0, 0), 10);
// Operations
bb.intersects(other);
bb.containsPoint(Vector(5, 5));
bb.merge(other);
bb.expand(Vector(15, 15));
Performance Tips #
- Use fast getters: For hot loops, use
positionX/positionYinstead ofpositionto avoid Vector allocation - Batch operations: Add/remove multiple objects before stepping
- Sleeping: Enable sleeping for inactive bodies to improve performance
- Spatial queries: Use spatial queries efficiently - they're fast but avoid calling them every frame for many objects
- Reindexing: Only call
reindexStatic()when you actually move static shapes
Platform Support #
This package supports:
- ✅ iOS
- ✅ Android
- ✅ macOS
- ✅ Linux
- ✅ Windows
- ✅ Web
Web Support #
On web, you must:
- Call
initializeChipmunk()before using any Chipmunk2D functions:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Required on web, no-op on native platforms
await initializeChipmunk();
runApp(MyApp());
}
- Include the
_dynamicImporthelper in yourweb/index.htmlfile:
<script>
// Required: Dart's js_interop cannot directly call the top-level import() function.
// This wrapper exposes import() as a window property so Dart can access it.
// Without this, the Chipmunk2D WASM module cannot be loaded on web.
window._dynamicImport = (path) => import(path);
</script>
The WASM module is automatically included in your Flutter web build - no additional setup required!
Chipmunk2D Version #
This package is built against Chipmunk2D 7.0.3. For API documentation and examples, refer to the official Chipmunk2D documentation.
Contributing #
Contributions are welcome! Please feel free to submit a Pull Request.
License #
This package is licensed under the MIT License, matching Chipmunk2D's license. See the LICENSE file for details.