Top Related Projects
Quick Overview
Box2D.js is a JavaScript port of the popular Box2D physics engine. It allows developers to simulate realistic 2D physics in web browsers, making it ideal for creating browser-based games and interactive applications that require physics simulations.
Pros
- Brings the power of Box2D to web browsers without plugins
- Supports both JavaScript and WebAssembly for optimal performance
- Integrates well with popular web frameworks and game engines
- Extensive documentation and examples available
Cons
- May have a steeper learning curve for those unfamiliar with physics engines
- Performance can be a concern for complex simulations on low-end devices
- Limited to 2D physics simulations
- Requires careful memory management in long-running applications
Code Examples
Creating a world and adding a body:
var world = new b2World(new b2Vec2(0, -10));
var bodyDef = new b2BodyDef();
bodyDef.type = b2_dynamicBody;
bodyDef.position.Set(0, 4);
var body = world.CreateBody(bodyDef);
var shape = new b2CircleShape();
shape.m_radius = 0.5;
body.CreateFixture(shape, 1.0);
Stepping the simulation:
var timeStep = 1.0 / 60.0;
var velocityIterations = 6;
var positionIterations = 2;
world.Step(timeStep, velocityIterations, positionIterations);
Applying forces to a body:
var force = new b2Vec2(10, 0);
var point = body.GetWorldCenter();
body.ApplyForce(force, point);
Getting Started
-
Include Box2D.js in your project:
<script src="https://cdnjs.cloudflare.com/ajax/libs/box2d/2.3.1/Box2D.min.js"></script>
-
Create a world and add bodies:
var world = new b2World(new b2Vec2(0, -10)); var bodyDef = new b2BodyDef(); bodyDef.type = b2_dynamicBody; bodyDef.position.Set(0, 4); var body = world.CreateBody(bodyDef); var shape = new b2CircleShape(); shape.m_radius = 0.5; body.CreateFixture(shape, 1.0);
-
Set up a game loop to step the simulation:
function gameLoop() { world.Step(1 / 60, 6, 2); requestAnimationFrame(gameLoop); } gameLoop();
-
Render the bodies using your preferred graphics library (e.g., Canvas, WebGL).
Competitor Comparisons
JavaScript 2D physics library
Pros of p2.js
- Lighter weight and faster performance for simpler 2D physics simulations
- More modern JavaScript codebase, easier to integrate with web projects
- Better documentation and examples for quick start
Cons of p2.js
- Less comprehensive feature set compared to Box2D.js
- Smaller community and fewer resources available
- May not handle complex simulations as robustly as Box2D.js
Code Comparison
p2.js:
var world = new p2.World({
gravity: [0, -9.82]
});
var boxShape = new p2.Box({ width: 1, height: 1 });
var boxBody = new p2.Body({
mass: 1,
position: [0, 5],
shape: boxShape
});
world.addBody(boxBody);
Box2D.js:
var world = new b2World(new b2Vec2(0, -9.8));
var bodyDef = new b2BodyDef();
bodyDef.type = b2Body.b2_dynamicBody;
bodyDef.position.Set(0, 5);
var body = world.CreateBody(bodyDef);
var shape = new b2PolygonShape();
shape.SetAsBox(0.5, 0.5);
body.CreateFixture(shape, 1.0);
Both libraries provide similar functionality for creating a physics world and adding bodies, but p2.js offers a more concise and modern syntax. Box2D.js, being a port of the C++ library, maintains a structure closer to its original implementation.
a 2D rigid body physics engine for the web ▲● ■
Pros of Matter.js
- Pure JavaScript implementation, making it easier to integrate and customize
- More lightweight and faster for simple simulations
- Better documentation and examples for quick start
Cons of Matter.js
- Less accurate physics simulation compared to Box2D.js
- Fewer advanced features and constraints
Code Comparison
Matter.js:
var engine = Matter.Engine.create();
var world = engine.world;
var box = Matter.Bodies.rectangle(200, 200, 80, 80);
Matter.World.add(world, box);
Matter.Engine.run(engine);
Box2D.js:
var world = new b2World(new b2Vec2(0, 10));
var bodyDef = new b2BodyDef();
bodyDef.type = b2Body.b2_dynamicBody;
bodyDef.position.Set(200, 200);
var body = world.CreateBody(bodyDef);
var shape = new b2PolygonShape();
shape.SetAsBox(40, 40);
body.CreateFixture(shape, 1.0);
Matter.js offers a more concise and intuitive API, while Box2D.js provides more granular control over physics properties. Matter.js is better suited for simple 2D physics simulations and games, while Box2D.js excels in more complex and accurate physics scenarios. The choice between the two depends on the specific requirements of your project, balancing ease of use with simulation accuracy and performance.
2D JavaScript Physics Engine
Pros of planck.js
- Written in TypeScript, offering better type safety and developer experience
- More actively maintained with recent updates and contributions
- Smaller file size, leading to faster load times in web applications
Cons of planck.js
- Less direct compatibility with existing Box2D resources and tutorials
- May have a smaller community and ecosystem compared to box2d.js
Code Comparison
box2d.js:
var world = new b2World(new b2Vec2(0, -10));
var bodyDef = new b2BodyDef();
bodyDef.type = b2Body.b2_dynamicBody;
bodyDef.position.Set(0, 4);
var body = world.CreateBody(bodyDef);
planck.js:
var world = planck.World({
gravity: planck.Vec2(0, -10)
});
var body = world.createBody({
type: 'dynamic',
position: planck.Vec2(0, 4)
});
Both libraries provide similar functionality for creating physics simulations, but planck.js offers a more modern and streamlined API. The code examples show how planck.js uses a more concise syntax for creating bodies and defining their properties, while box2d.js requires separate object instantiations for body definitions and vector creation.
Box2D is a 2D physics engine for games
Pros of Box2D
- Written in C++, offering better performance for native applications
- More extensive documentation and community support
- Regular updates and maintenance from the original creator
Cons of Box2D
- Requires compilation for different platforms
- Not directly usable in web browsers without additional porting
- Steeper learning curve for developers unfamiliar with C++
Code Comparison
Box2D (C++):
b2Vec2 gravity(0.0f, -10.0f);
b2World world(gravity);
b2BodyDef groundBodyDef;
b2Body* groundBody = world.CreateBody(&groundBodyDef);
Box2D.js (JavaScript):
var gravity = new b2Vec2(0, -10);
var world = new b2World(gravity);
var groundBodyDef = new b2BodyDef();
var groundBody = world.CreateBody(groundBodyDef);
Box2D.js is a JavaScript port of the original Box2D physics engine, making it easier to use in web-based projects. It allows developers to implement 2D physics simulations directly in the browser without the need for plugins or compilation. However, it may have slightly lower performance compared to the native C++ version and might lag behind in terms of feature updates.
Both libraries provide similar functionality for 2D physics simulations, with the main difference being the target platform and ease of integration into different types of projects.
Lightweight 3d physics engine for javascript
Pros of Oimo.js
- Lighter and faster than Box2d.js, making it suitable for mobile devices and web applications
- Simpler API, easier to learn and implement for basic physics simulations
- Better integration with Three.js for 3D graphics
Cons of Oimo.js
- Less accurate physics simulation compared to Box2d.js
- Fewer features and less comprehensive documentation
- Smaller community and fewer resources available
Code Comparison
Box2d.js:
var world = new b2World(new b2Vec2(0, -10));
var bodyDef = new b2BodyDef();
bodyDef.type = b2Body.b2_dynamicBody;
bodyDef.position.Set(0, 4);
var body = world.CreateBody(bodyDef);
Oimo.js:
var world = new OIMO.World({ gravity: [0, -9.8, 0] });
var body = world.add({ type: 'sphere', size: [1], pos: [0, 4, 0], move: true });
Both libraries provide physics simulation for JavaScript applications, but Oimo.js offers a more streamlined approach with a simpler API, while Box2d.js provides more accurate and feature-rich simulations at the cost of complexity and performance.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
box2d.js
Demo: http://kripken.github.io/box2d.js/demo/webgl/box2d.html
WebAssembly demo: http://kripken.github.io/box2d.js/demo/webgl/box2d.wasm.html
Example code to give you an idea of the API: https://github.com/kripken/box2d.js/blob/master/demo/webgl/box2d.html#L14
box2d.js is a direct port of the Box2D 2D physics engine to JavaScript, using Emscripten. The source code is translated directly to JavaScript, without human rewriting, so functionality should be identical to the original Box2D.
box2d.js is zlib licensed, just like Box2D.
Discussion takes place on IRC at #emscripten on Mozilla's server (irc.mozilla.org)
Details
The automatically generated bindings have been tested to the extent that can be found in the examples in the 'testbed'. For general notes on using the bindings, see the ammo.js project (a port of Bullet to JavaScript using Emscripten), many of the details of wrapping classes and so forth are identical.
It seems to be running ok on at least the following:
- Desktop PC (Linux) - Chrome22, Opera12, Firefox16
- Desktop PC (OSX) - Chrome22, Opera12, Firefox16
- Desktop PC (Win7) - Chrome22, Opera12, Firefox16
- iOS 5 - Safari, Chrome, Dolphin
- Android ICS - Chrome18
- Android JB - Chrome18, Dolphin9
Testbed
The demo/html5canvas folder contains an example web page and script files to reproduce the original Box2D testbed, with similar controls and features.
Demo: http://www.iforce2d.net/embox2d/testbed.html
Like the original C++ version, the testbed is set up so that adding another test scene is easy. Look in the tests folder and find the template.js file....
- Copy template.js and rename it.
- In the renamed file, replace all occurrences of 'embox2dTest_template' with your test name.
- Fill in the setup function.
- Optionally, fill in the other functions.
- Include the new file at the beginning of testbed.html with the other tests.
- Add the new test option to the "testNumber" select box in test.html
R.U.B.E testbed
The demo/rube_testbed folder contains the testbed with scenes which were exported from the R.U.B.E editor
Building
$ /PATH/TO/EMSCRIPTEN emmake make
To build latest (2.3.1) version:
$ /PATH/TO/EMSCRIPTEN emmake make VERSION=latest
Also, You can build the debug version of javascript file (with source maps support):
$ /PATH/TO/EMSCRIPTEN emmake make VERSION=latest BUILD=debug
This runs emscripten and uses it to compile a version of the Box2D source code stored within the box2d.js git. This source code has been modified to add constructors to some objects to ensure that emscripten will generate bindings for them.
Currently, you need to use a very recent Emscripten to build, version 1.23.0 or later (master branch as of Aug 21 2014) to build box2d.js. See http://kripken.github.io/emscripten-site/docs/building_from_source/building_emscripten_from_source_using_the_sdk.html#building-emscripten-from-source-using-the-sdk
Usage (WebIDL bindings)
The current bindings are created with the WebIDL binder. Read Box2D_v2.2.1.idl to see the class, methods, and attributes that are bound.
See test.js for a small working example.
Note: To improve readability all code snippets below assume that everything in the 'Box2D' namespace has been made available! (Check the 'using' function in helpers/embox2d-helpers.js
for details.)
Class member variable access
The values of public member variables of Box2D classes (mostly the definition classes) can be set and accessed using the generated functions, which will be the variable name prefixed with set_
or get_
, eg.
//C++
circleShape.m_radius = 2;
//javascript
circleShape.set_m_radius( 2 );
Vector manipulation
b2Vec2 vectors can be created like:
var myVec = new b2Vec2( 1.2, 3.4 );
As mentioned above, the individual components of vectors can be obtained with the get_x()
and get_y()
functions.
Vectors can be assigned with the = operator but if you are coming from a C++ background, you may be caught out by the fact that this does not result in two independent variables. To get the same behavior as the original C++ assignment you can copy the components like:
var anotherVec = new b2Vec2( vec.get_x(), vec.get_y() );
Alternatively the assignment, addition and subtraction operators can be replaced with the functions below (however, experience shows these to be somewhat dodgy...)
operator name in JS
-------- ----------
= op_set
+ op_add
- op_sub
Creating a world
A typical world can be created like:
var world = new b2World( new b2Vec2(0.0, -10.0) );
Creating bodies
A static body can be created like:
var groundBody = world.CreateBody( new b2BodyDef() );
... and dynamic/kinematic bodies like:
var bodyDef = new b2BodyDef();
bodyDef.set_type( b2_dynamicBody );
var dynamicBody = world.CreateBody( bodyDef );
Creating fixtures
A circle fixture with density 1 and default values for everything else (friction, restitution etc):
var circleShape = new b2CircleShape();
circleShape.set_m_radius( 0.5 );
body.CreateFixture( circleShape, 1.0 );
A circle fixture with some more specific settings:
var fixtureDef = new b2FixtureDef();
fixtureDef.set_density( 2.5 );
fixtureDef.set_friction( 0.6 );
fixtureDef.set_shape( circleShape );
body.CreateFixture( fixtureDef );
An edge shape:
var edgeShape = new b2EdgeShape();
edgeShape.Set( new b2Vec2( -20, 3 ), new b2Vec2( 20, 7 ) );
fixtureDef.set_shape( edgeShape );
body.CreateFixture( fixtureDef );
Creating polygon shapes seems to be somewhat messy with the current bindings, so the recommended way is to use the createPolygonShape
helper function in embox2d-helpers.js:
var verts = [];
verts.push( new b2Vec2( 7,-1 ) );
verts.push( new b2Vec2( 8,-2 ) );
verts.push( new b2Vec2( 9, 3 ) );
verts.push( new b2Vec2( 7, 1 ) );
var polygonShape = createPolygonShape( verts );
fixtureDef.set_shape( polygonShape );
body.CreateFixture( fixtureDef );
Likewise for chain shapes: Edit: seems to be a problem with this, best to avoid chain shapes for now
var chainShape = createChainShape( verts, true ); //true for closed loop, false for open chain
fixtureDef.set_shape( chainShape );
body.CreateFixture( fixtureDef );
Creating joints
Example revolute joint:
var jointDef = new b2RevoluteJointDef();
jointDef.set_bodyA( body1 );
jointDef.set_bodyB( body2 );
jointDef.set_localAnchorA( new b2Vec2( 1, 2 ) );
jointDef.set_localAnchorB( new b2Vec2( 3, 4 ) );
jointDef.set_collideConnected( true );
var revoluteJoint = Box2D.castObject( world.CreateJoint( jointDef ), b2WheelJoint );
Using debug draw
Create a JSDraw
object, and supply implementations of the draw methods. (Note: All methods must
be implemented even if unused.)
var debugDraw = new Box2D.JSDraw();
debugDraw.DrawSegment = function(vert1Ptr, vert2Ptr, colorPtr ) {
setColorFromDebugDrawCallback( colorPtr );
drawSegment( vert1Ptr, vert2Ptr );
}
// Empty implementations for unused methods.
debugDraw.DrawPolygon = function() {};
debugDraw.DrawSolidPolygon = function() {};
debugDraw.DrawCircle = function() {};
debugDraw.DrawSolidCircle = function() {};
debugDraw.DrawTransform = function() {};
world.SetDebugDraw( debugDraw );
The parameters of the draw methods will be pointers to data inside emscripten's innards, so you'll need to wrap them to get the data type you are looking for. Here are the two functions mentioned above, as an example of how you would wrap the passed b2Color
and b2Vec2
parameters and use them in your drawing. This example is to draw on a HTML5 canvas:
function setColorFromDebugDrawCallback( colorPtr ) {
var color = Box2D.wrapPointer( colorPtr, b2Color );
var red = (color.get_r() * 255) | 0;
var green = (color.get_g() * 255) | 0;
var blue = (color.get_b() * 255) | 0;
var colorStr = red + "," + green + "," + blue;
context.fillStyle = "rgba(" + colorStr + ",0.5)";
context.strokeStyle = "rgb(" + colorStr + ")";
}
function drawSegment( vert1Ptr, vert2Ptr ) {
var vert1 = Box2D.wrapPointer( vert1Ptr, b2Vec2 );
var vert2 = Box2D.wrapPointer( vert2Ptr, b2Vec2 );
context.beginPath();
context.moveTo( vert1.get_x(), vert1.get_y() );
context.lineTo( vert2.get_x(), vert2.get_y() );
context.stroke();
}
Accessing the vertex arrays passed to other functions such as DrawPolygon are somewhat more tricky - please see the embox2d-html5canvas-debugDraw.js source for an example.
Using collision events
Contact listener callbacks are also implemented with customizeVTable.
listener = new JSContactListener();
listener.BeginContact = function (contactPtr) {
var contact = Box2D.wrapPointer( contactPtr, b2Contact );
var fixtureA = contact.GetFixtureA();
var fixtureB = contact.GetFixtureB();
// now do what you wish with the fixtures
}
// Empty implementations for unused methods.
listener.EndContact = function() {};
listener.PreSolve = function() {};
listener.PostSolve = function() {};
world.SetContactListener( listener );
Using world callbacks
Callbacks for other uses such as world querying and raycasting can also be implemented with customizeVTable. Here is the callback used in the 'testbed' to find the fixture that the mouse cursor is over when the left button is clicked:
myQueryCallback = new JSQueryCallback();
myQueryCallback.ReportFixture = function(fixturePtr) {
var fixture = Box2D.wrapPointer( fixturePtr, b2Fixture );
if ( fixture.GetBody().GetType() != Box2D.b2_dynamicBody ) //mouse cannot drag static bodies around
return true;
if ( ! fixture.TestPoint( this.m_point ) )
return true;
this.m_fixture = fixture;
return false;
};
The callback is used like:
myQueryCallback.m_fixture = null;
myQueryCallback.m_point = new b2Vec2( mouseX, mouseY );
world.QueryAABB( myQueryCallback, aabb ); // the AABB is a tiny square around the current mouse position
if ( myQueryCallback.m_fixture ) {
//do something with the fixture that was clicked
}
Using a Destruction Listener
The standard b2DestructionListener class can't be used directly from javascript, as it has two methods that share
the same name (SayGoodbye
), and differ only by the type of their single parameter.
To listen for destruction events, do:
var myDestructionListener = new JSDestructionListener()
myDestructionListener.SayGoodbyeJoint = function(joint) {
var joint = Box2D.wrapPointer( joint, b2Joint );
}
myDestructionListener.SayGoodbyeFixture = function(fixture) {
var fixture = Box2D.wrapPointer( fixture, b2Fixture );
}
Top Related Projects
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot