p2-es
p2-es is a 2D rigid body physics engine written in JavaScript. Features include collision detection, contacts, friction, restitution, motors, springs, advanced constraints and various shape types.
Demos | Examples | Documentation
This is a maintained fork of p2.js, originally created by Stefan Hedman @schteppe. It is a type-safe flatbundle (esm and cjs) which allows for tree shaking and usage in modern environments.
If you're using three.js in a React environment with react-three-fiber, check out use-p2! It's a wrapper around p2-es that runs in a web worker.
Getting Started
NPM
npm install p2-es
yarn add p2-es
CDN
You can also import the esm bundle with unpkg:
<script type="module">
import * as p2 from 'https://www.unpkg.com/p2-es@1.1.6/dist/p2-es.js'
import * as p2 from 'https://www.unpkg.com/p2-es/dist/p2-es.js'
</script>
If you would like to use ordinary Array
instead of Float32Array
, define P2_ARRAY_TYPE
globally before loading the library.
<script type="text/javascript">
P2_ARRAY_TYPE = Array
</script>
<script type="module">
import * as p2 from 'p2-es.js'
</script>
Sample code
The following example uses the World, Circle, Body and Plane classes to set up a simple physics scene with a ball on a plane.
import * as p2 from 'p2-es'
const world = new p2.World({
gravity: [0, -9.82],
})
const circleBody = new p2.Body({
mass: 5,
position: [0, 10],
})
const circleShape = new p2.Circle({ radius: 1 })
circleBody.addShape(circleShape)
world.addBody(circleBody)
const groundBody = new p2.Body({
mass: 0,
})
const groundShape = new p2.Plane()
groundBody.addShape(groundShape)
world.addBody(groundBody)
const fixedTimeStep = 1 / 60
const maxSubSteps = 10
let lastTime = 0
function animate(time) {
requestAnimationFrame(animate)
const deltaTime = (time - lastTime) / 1000
world.step(fixedTimeStep, deltaTime, maxSubSteps)
renderCircleAtPosition(circleBody.interpolatedPosition)
lastTime = time
}
requestAnimationFrame(animate)
To interact with bodies, you need to do it after each internal step. Simply attach a "postStep" listener to the world, and make sure to use body.position
here - body.interpolatedPosition
is only for rendering.
world.on('postStep', function (event) {
circleBody.force[0] -= 100 * circleBody.position[0]
})
Supported collision pairs
| Circle | Plane | Box | Convex | Particle | Line | Capsule | Heightfield | Ray |
---|
Circle | Yes | - | - | - | - | - | - | - | - |
Plane | Yes | - | - | - | - | - | - | - | - |
Box | Yes | Yes | Yes | - | - | - | - | - | - |
Convex | Yes | Yes | Yes | Yes | - | - | - | - | - |
Particle | Yes | Yes | Yes | Yes | - | - | - | - | - |
Line | Yes | Yes | (todo) | (todo) | - | - | - | - | - |
Capsule | Yes | Yes | Yes | Yes | Yes | (todo) | Yes | - | - |
Heightfield | Yes | - | Yes | Yes | (todo) | (todo) | (todo) | - | - |
Ray | Yes | Yes | Yes | Yes | - | Yes | Yes | Yes | - |
Note that concave polygon shapes can be created using Body.fromPolygon.
Building
Make sure you have git, Node.js v14+ and Yarn installed
git clone https://github.com/pmndrs/p2-es.git && cd p2-es
yarn
(cd packages/p2-es && yarn build)
yarn build
npx http-server apps/p2-es-website/dist