This page is intended to help you get started using dyn4j. You can post any questions on the forums, but please read this page first before doing so.
Table of Contents
Latest versions of dyn4j can be found on Maven Central.
All binaries builds posted on the download page are compiled under Java 1.6 and have no dependencies.
If you are intent on building the source from the repository here are few tips:
- The trunk branch is the development branch and will contain the latest code but may be unstable.
- For stable builds look in the tags folder and connect to the desired release version.
- There may be other branches available in the branches folder, labeled for specific purposes.
Add To The Classpath
To see the classes you must add the JAR to the classpath of your project.
For Eclipse perform the following steps:
- Copy the dyn4j.jar to your project in eclipse.
- Right click on the dyn4j.jar and select Build Path → Add to Build Path
Watch the video below for a full description on how to get a new Eclipse project setup to use dyn4j:
When building your project on the command line add the jar in the -classpath flag for example:
javac ... -classpath /path/to/jars/dyn4j.jar
Currently the releases are not signed. This will cause the user of your application to receive an error message (if you deploy via JNLP or Applet and require all permissions) about the jar not being signed.
In the meantime, you will need to sign the jars yourself. Later releases will be signed using an CA if there is enough demand.
Let’s start with some basics about how your game interfaces with the physics engine. Any real world object that will need to interact with other objects is called a Body. Bodies interact with one another in a World. Bodies can also be joined together with other Bodies by Joints.
To setup your scene:
- Create a World instance
- Create your Bodies and add them to the World
- Create your Joints and add them to the World
- Call the World.update(double) method in your game loop
Creating The World
The World class is in the dynamics package. To create the World object for your game you only need to pass it a Bounds object. The Bounds object controls the maximum bounds of the scene. If an body travels (fully) outside the bounds the state of the body will be set to “inactive” and will no longer be interacting with the World or other bodies.
Most games will use the provided AxisAlignedBounds class which defines a rectangular area. You can also use the default constructor of the World class to create a World that has no Bounds. Be careful when doing this since numeric overflow can happen.
Once the World is created there a number of things you may want to configure. The most common configurable item is gravity. The default gravity is 9.8 m/s pointing in the negative y direction. Refer to the Javadocs for more information on other configuration items.
A Body represents any object in your scene that you want to interact with other objects using physics. A body can be comprised of one or more Convex Shapes. Each shape must be wrapped in a BodyFixture. A BodyFixture provides a clear distinction between geometry and dynamics by adding the extra information for a shape such as density, friction, and restitution.
Here is a simple diagram explaining the relationship:
There are a number of Convex Shapes provided including Circle, Polygon, Rectangle, etc all contained in the geometry package.
Here are a few tips to creating shapes:
- You can also use any methods in the Geometry class for alternate ways to create shapes.
- Rectangle and Circle objects created always have their center at (0, 0). Segments, Polygons, and Triangles have their centers at the center of the points (average or area based center).
- Some of the Shape creation methods in the Geometry class create shapes with their centers at the origin. All the methods in the Geometry class make copies of the input points and arrays.
- Only convex shapes are supported. Concave shapes are supported by decomposing the concave shape into multiple convex shapes (dyn4j provides classes to perform the decomposition of simple polygons).
After creating the desired shape you can do two things to add it to a body. You can create a new BodyFixture object passing the shape to it, configure it, then add it to the body by using the addFixture method. Or you can use the addFixture(Convex) method to create a default fixture that will automatically be added to the body and returned so you can configure it.
If you use multiple shapes for a body use the Shape class’s translate and rotate methods to place the shape at the right position and orientation in local coordinates.
- Note: This directly modifies the shape’s vertices and center.
The mass of a body is created by its respective shapes. Each shape type contains a createMass method which will use geometry and the density configured in its respective BodyFixture to create a Mass object. The density units are kg / m2. The density for a shape is set via the setDensity method in the BodyFixture class.
After adding Shapes/BodyFixtures to your body, be sure to call one of the setMass methods to set the mass. The default mass is an infinite mass centered at the origin.
- You can use the MassType parameter to create specialized masses like infinite mass bodies.
The setMass methods will also compute what is called the rotation disc radius. This is used in continuous collision detection and is dependent on the center of mass being computed.
- The rotation disc radius is the radius of the disc created by a rotating body (imagine a body rotated 360 degrees about its center).
Finally add the body to the World by calling the World.addBody(Body) method.
A Joint represents a connection between two bodies that limit motion. A connection might be a frame of a car connecting two wheels or a spring connecting a wheel to a car frame.
All Joint classes are contained in the dynamics.joint package. Each joint class may have a different constructor depending on the type.
Once the joint is created it can be added to the World by calling the World.addJoint(Joint) method.
See the Joints page for more details about each Joint.
General Creation Tips
The BodyFixture, Body, Joint, and World classes, among others, typically only have minimal constructors. This allows for less confusion in the source.
For example the DistanceJoint class only accepts two anchor points and the bodies. To use the optional features, call the setXXX methods after creation of the object:
// creates a standard fixed distance joint
DistanceJoint dj = new DistanceJoint(b1, b2, p1, p2);
// to make it a spring-damper
// or for a RevoluteJoint
RevoluteJoint rj = new RevoluteJoint(wheel, frame, pivot);
// to use a motor
// or for a fixture
BodyFixture f = new BodyFixture(rect);
// or for a body
Body b = new Body();
b.setVelocity(new Vector2(0.0, 2.0));
Integrating Into The Game Loop
Most, if not all, games use active rendering and something called a “game loop” to poll for input, update graphics, etc. To allow simulation of the scene the World object has two methods that must be called from the game loop: World.update(double) or World.updatev(double). These methods must be passed the elapsed time from the last iteration in seconds.
The World.updatev(double) method can be used if you prefer a variable time step or would like to control when the World updates yourself. The World.update(double) method will only update given the step frequency set in the Settings object.
- Note: Variable time steps can reduce accuracy and stability.
There are a number of RuntimeExceptions that are thrown. Exceptions like these are typically thrown when the creation of an object fails due to invalid arguments. These exceptions should rarely occur.
For example, adding a null Body to the World object throws a NullPointerException. The runtime exceptions you may encounter include:
- NullPointerException – usually caused by passing null instead of a object reference to a constructor or setXXX method.
- IllegalArgumentException – usually caused by passing an invalid value that has a predefined range or restriction.
- UnsupportedOperationException – usually caused by attempting to modify an immutable object, Transform.IDENTITY for example.
- IndexOutOfBoundsException – usually caused by referencing an index of a BodyFixture, Shape, etc that is out of bounds. Can also because by supplying the wrong sized list or array to a method that expects a certain size.
Most of these exceptions are obvious or documented in the source and Javadocs (using text like “in the range of [0, 1]”) or by @throws javadoc documentation.
In addition, the Sandbox testing application has a number of predefined tests that can be exported to Java code for reference. You can also play with various features of the engine, creating bodies, fixtures, and joints and run, stop, and step the simulation.