Open-source project
dyn4j/dyn4j avatar
dyn4j/dyn4j

dyn4j: a pure Java 2D collision detection and physics engine

Java Collision Detection and Physics Engine

541 stars85 forksJavaBSD-3-Clause

At a glance

What is it?
dyn4j is a 100 percent Java 2D collision detection and physics engine, free for commercial and non-commercial use, with rigid bodies built from convex fixtures, a pipeline for detection, manifold generation and resolution, and a range of joints for linking bodies together. It suits a Java developer who needs 2D physics without a native dependency, and the detail to plan around is that the latest tagged release is from 2018 while the Maven artifact carries version 6.0.0.
Who is it for?
Adopt dyn4j if you need 2D physics in a Java application and want to avoid a native library, since the whole engine is Java and the API is small enough to learn in an afternoon.
Can I use it commercially?
Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 98 days ago.
What is it written in?
Mainly Java, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What the project is

dyn4j is a 100% Java 2D collision detection and physics engine, designed to be fast, stable, extensible and easy to use. It is free for use in commercial and non-commercial applications.

That last sentence is worth pausing on, because it removes the usual licensing question for an engine of this kind. A physics library that is free for commercial use can sit in a shipped product without a negotiation.

The project is split into two repositories. The main project and its tests are managed here, and a separate dyn4j-samples repository holds a collection of samples to help get started. That separation is the same pattern used by other libraries that need a substantial example application, since the samples need a rendering framework and the engine itself does not.

The engine's own subject matter is the topic tags: collision-detection, continuous-collision-detection, convex-decomposition, convex-hull-algorithms, physics-engine and simulation. Continuous collision detection in particular is the feature that separates a real physics engine from a naive overlap test, since it catches a fast-moving body passing through a thin wall between two frames.

The homepage is dyn4j.org, the licence is BSD 3-clause, the primary language is Java, the default branch is master, and the last push was on 2026-07-18. The language badge in the README states Java 6 or newer, and the requirements section says Java 1.6+.

The release history shown alongside the project is the interesting part. The listed releases are 3.3.0 from 2018-04-15, 3.2.4 from 2017-05-02 and 3.2.3 from 2016-09-04, but the README's own Maven snippet asks for version 6.0.0, and there is a note that Releases are no longer being created as of 3.4.0. So the GitHub tags stopped, and the artifact moved forward through Maven Central instead.

Getting the library onto your classpath

Adding dyn4j to a project is a Maven dependency, and the coordinates are the standard ones:

xml
<dependency>
    <groupId>org.dyn4j</groupId>
    <artifactId>dyn4j</artifactId>
    <version>6.0.0</version>
</dependency>

The dependency is available from Maven Central or from GitHub Packages, and if you are not using Maven you can download the jar from either of those links. There is also a javadoc badge pointing at javadoc.io, which is the usual way to browse the API documentation of a published artifact.

The version gap is the thing to notice here. The README asks for 6.0.0, the latest tagged GitHub release is 3.3.0 from 2018, and the note says releases are no longer being created as of 3.4.0. The practical consequence is that if you look at the repository's release list to decide what version you are getting, you will be reading a stale picture. Maven Central is the place where the current version lives, and the code coverage badge in the README, at 96.7 percent, is the other sign of an actively tested codebase.

The Getting Started section points at a video for a quick orientation, and then walks through six steps, each of which is a code block in the README. The six steps are the shape of a minimal simulation: create a world, add bodies, add joints, run the simulation, and read the output back out.

Two resources sit at the end of the chain. The dyn4j-samples sub project gives a jump start with a simple Java2D framework, and there is full getting started documentation at dyn4j.org/pages/getting-started, alongside advanced pages, release notes in the repository, the latest javadocs and a blog.

The world, the pipeline and the settings

Step 2 is the whole world in one line:

java
World<Body> world = new World<Body>();

The generic parameter is worth noticing. `World<Body>` says the world holds bodies of type `Body`, and the README uses World<Body>, tying the world to a body type parameter rather than hard-coding one body class.

The world is created with default settings, and the defaults are described: they use the meter-kilogram-seconds system and include the default pipeline classes for collision detection, manifold generation, and collision resolution. You can adjust the pipeline classes using the respective methods on the World class, and update the settings using the getSettings method.

The three stages of the pipeline are the architecture of the engine and they are worth understanding on their own terms.

Collision detection finds which pairs of shapes overlap. Manifold generation computes the contact information for those pairs, the points and normals that describe how the shapes are touching. Collision resolution turns that contact information into changes to velocity and position so the bodies stop interpenetrating and behave as though they have mass and bounce.

Having these as separate, replaceable stages is what makes the engine extensible in a meaningful way. A developer who wants different contact behaviour, a different solver, or a broad-phase that suits a particular scene can substitute one stage without rewriting the others. The same replaceability applies to the unit system, since the settings object controls it, and the choice of SI units by default means the numbers in your code are metres and kilograms rather than pixels.

That distinction between pixels and metres is worth internalising before writing any code. A physics engine integrated with a rendering layer usually has a conversion factor between the two, and getting that wrong is the usual source of a simulation that looks wrong at every scale.

Bodies, fixtures and the convex rule

Step 3 adds a body, and the example is four lines:

java
Body body = new Body();
body.addFixture(Geometry.createCircle(1.0));
body.translate(1.0, 0.0);
body.setMass(MassType.NORMAL);
world.addBody(body);

The vocabulary here is the important part. A Body is the primary unit of simulation and completely rigid. A Body is comprised of one or more BodyFixtures, and each Fixture has one Shape.

The rule that catches people out is stated directly: while the shapes of dyn4j are all convex, and must be, a collection of these shapes can be used to create a body that is not. So a non-convex body, a concave polygon, an L-shape, a letter C, is built by assembling several convex fixtures into one body rather than by describing a concave shape.

That is the standard approach in every 2D engine, and the reason is algorithmic. Convex shapes have well-defined separating axes, which makes overlap tests cheap and reliable. Concave shapes do not, and a naive concave overlap test produces the classic failure where a shape passing through the notch of a C is reported as not colliding.

The body is placed in the scene with translate or rotate before being added, and then it must be given a mass by calling a setMass method. The mass type is typically MassType.NORMAL or MassType.INFINITE. With NORMAL, the mass is calculated based on the shapes. An INFINITE mass body might represent a floor, ground, or something immovable.

So the last step of adding a body is not optional bookkeeping. A body with no mass either falls through the floor or behaves strangely, and the distinction between a normal body and an infinite one is what makes a static world possible.

The geometry construction is also where the convex hull algorithms in the topic tags come in, since `Geometry` is the factory for the available shapes, a circle in this example with a radius of 1.0.

Joints, stepping the simulation and reading the output

Step 4 attaches a joint, and joints are how bodies are linked:

java
PinJoint<Body> joint = new PinJoint<Body>(body, new Vector2(0, 0));
joint.setSpringEnabled(true);
joint.setSpringDamperEnabled(true);
joint.setMaximumSpringForceEnabled(true);
joint.setSpringFrequency(8.0);
joint.setSpringDampingRatio(0.3);
joint.setMaximumSpringForce(1000.0);
world.addJoint(joint);

A Joint is a constraint on the motion of one or more Bodies. There are many joint types that serve different purposes, and generally joints are used to link bodies together in a specified way. Bodies can have multiple joints attached to them, which makes for some interesting combinations. The documentation advises reviewing each joint's class documentation for details on usage.

The PinJoint in the example pins a body to a world anchor at the origin, and then the spring configuration turns it into a soft constraint rather than a rigid one. The parameters are the ones you would expect from a spring model: a frequency, a damping ratio, and a maximum force. Setting the spring enabled and the damper enabled separately is a deliberate choice, since a spring without damping oscillates forever and the engine will not apply one for you.

Step 5 runs the simulation:

java
for (int i = 0; i < 100; i++) {
    world.step(1);
}

The argument is the time step. In a GUI application you would call the World.update(elapsedTime) method in the render loop instead, and the documentation is explicit that each time the world is advanced forward in time, which may or may not occur when using the update method, the bodies in it are moved based on the world gravity, if any, and will interact with other bodies placed in the world.

That note about the update method not necessarily advancing time is a real distinction, not a typo. The step and update methods exist for two different situations, and mixing them up produces a simulation that runs at the wrong speed.

Step 6 reads the results back, and the key idea is the Transform. After each update of the world, each body's Transform reflects the changes caused by the simulation, and each Body stores its current position and rotation in a Transform. Using the Transform you can convert from local body space to world space coordinates. The example walks the bodies, takes the world centre, then for each fixture takes the shape, checks whether it has vertices by testing for the Wound interface, and converts each vertex into world space with getWorldPoint.

The interface test is the detail to notice. All shapes in dyn4j share the Convex base, but only some of them have vertices, a circle does not, so the code asks what the shape actually is before assuming it can be iterated.

Editorial conclusion

Adopt dyn4j if you need 2D physics in a Java application and want to avoid a native library, since the whole engine is Java and the API is small enough to learn in an afternoon. Do not expect the release history to tell you which version you have, because the GitHub releases stopped being created as of 3.4.0 and the Maven artifact moved on to 6.0.0 separately, and check first whether your build still targets Java 1.6, since that is the stated requirement while the current artifact may expect more.

Frequently asked questions

What is dyn4j?

It is a 100% Java 2D collision detection and physics engine, designed to be fast, stable, extensible and easy to use, and it is free for use in commercial and non-commercial applications. The licence is BSD 3-clause and the engine supports collision detection, continuous collision detection, convex decomposition and hull algorithms.

How do I add dyn4j to a Maven project?

Add the dependency with groupId org.dyn4j, artifactId dyn4j and version 6.0.0, available from Maven Central or GitHub Packages. If you are not using Maven you can download the jar directly, and the note that Releases are no longer being created as of 3.4.0 explains why the GitHub release list stops at 3.3.0 while the artifact is at 6.0.0.

What do I need to know about dyn4j bodies and fixtures?

A Body is the primary unit of simulation and is completely rigid, made up of one or more BodyFixtures, each of which has one Shape. All shapes in dyn4j are convex and must be, but a collection of them can form a body that is not convex. A body must be given a mass with setMass, usually MassType.NORMAL or MassType.INFINITE for something immovable like a floor.

How do I run and read a dyn4j simulation?

Call world.step(1) to advance the simulation by one time step, or World.update(elapsedTime) in the render loop of a GUI application. After each update, each body's Transform holds its current position and rotation, and you convert local shape vertices into world space with body.getWorldPoint, checking the shape's type first since only shapes implementing Wound have vertices.

What is the dyn4j pipeline?

The default World settings include the default pipeline classes for collision detection, manifold generation and collision resolution, and the units default to the meter-kilogram-seconds system. You can adjust the pipeline classes using the respective methods on the World class and change the settings through getSettings, which is what makes the engine extensible.

Is dyn4j still being maintained?

The repository is not archived and the last push was on 2026-07-18. The listed GitHub releases stop at 3.3.0 from 2018-04-15 because releases are no longer being created as of 3.4.0, with the artifact version tracked through Maven Central instead. The README reports code coverage of 96.7 percent and points to a separate dyn4j-samples repository for examples.

Official sources

  1. dyn4j/dyn4j on GitHub
  2. License: BSD-3-Clause
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/dyn4j-dyn4j.svg)](https://hysenlabs.com/projects/dyn4j-dyn4j)

Was this useful?