Physix Helpers - GameDevWeek/CodeBase GitHub Wiki

We're using Box2D for physics, which comes with LibGDX. You are free to ignore the classes we provide with this tutorial, but we found it helps reducing the workload a lot.

Commons-GDX contains a couple of Helper classes to get started with physics development:

  • A body component
  • A modifier component
  • A debug-renderer system
  • Two physics systems (with and without fixed step)
  • Builder patterns to easily create bodies and fixtures.
  • Component-aware contact listeners.

These are located in de.hochschuletrier.gdw.commons.gdx.physix.

Components

PhysixBodyComponent

You can add this component to an entity to link a Box2D body to it. This is usually done like this:

body = engine.createComponent(PhysixBodyComponent.class);
body.init(bodyDef, physixSystem, entity);
body.createFixture(fixtureDef);
entity.add(body);

Keep in mind that you can't add this component during a world step(update).

Removing this component will remove the body from the world as well. Since Ashley removes components after system updates, you can do this without worries about the world step.

PhysixModifierComponent

You probably know, that you can't add, remove or move bodies during a world step (update). To make it possible, this component has been created. With it you can schedule code to be executed at a suitable time.

The basic syntax is:

PhysixModifierComponent modifier= engine.createComponent(PhysixModifierComponent.class);
entity.add(modifier);

modifier.schedule(() -> {
    // add the body component here
});

Keep in mind: To remove a body, just remove the PhysixBodyComponent. No need to schedule it!

When all scheduled code has been run, the modifier-component will be removed! So if you want to modify a body, you should first check, if a modifier-component already exists:

PhysixModifierComponent modifier = ComponentMappers.physixModifier.get(entity);
if(!modifier) {
    modifier = engine.createComponent(PhysixModifierComponent.class);
    entity.add(modifier);
}

modifier.schedule(() -> {
    // modify the body here
});

Systems

PhysixDebugRenderSystem

This system uses a Box2DDebugRenderer to render debug physics using the current ProjectionMatrix of DrawUtil.batch. You don't need to know anything about rendering to add this to your game. As long as DrawUtil.batch is used for drawing, you should be fine by just adding this system to your Ashley Engine.

PhysixSystem

This system creates and updates a Box2D world for you. It also handles PhysixModifierComponent for you. Check out the public methods for stuff like:

  • Box2D to World coordinates conversion and vice versa.
  • Changing gravity
  • Reset the whole world

PhysixSystemFixedStep

PhysixSystemFixedStep extends PhysixSystem to allow for a fixed time-step.

Online tutorials will tell you to use a fixed step to avoid problems. In my test cases, it always caused stuttering, so I made this optional. Use if you encounter simulation problems with PhysixSystem. You can reduce the stuttering by using a higher framerate for the physics than the rendering. For example, if you render at 60 FPS, use a framerate of 120 or even 240 for physics.

PhysixBodyDef / PhysixFixtureDef

These are Fluent Interfaces (a chained Builder-Pattern) to help you construct a BodyDef or a FixtureDef easily.

An example for how to create a new bodydef:

PhysixBodyDef bodyDef = new PhysixBodyDef(BodyType.DynamicBody, physixSystem)
    .position(100, 100)
    .fixedRotation(true)
    .position(x, y);

PhysixBodyDef extends Box2Ds BodyDef, so you can use it anwywhere BodyDef is expected! Same goes for PhysixFixtureDef.

Aside from allowing you to set different properties of the definition, it also takes care of world to box2d coordinate conversion.

An example how to create a circle shape fixture:

PhysixFixtureDef fixtureDef = new  PhysixFixtureDef(physixSystem)
    .density(5)
    .friction(0.2f)
    .restitution(0.4f)
    .shapeCircle(30);
body.createFixture(fixtureDef);

Contact Listeners

PhysixComponentAwareContactListener

Of course, you are free to implement your own contact listener, but this one has a couple of benefits:

  • You can add listeners for specified component classes.
  • You can always be sure that the first body in the contact has the specified component class.
  • You get the PhysixBodyComponent (and its entity) from the contacts for free (no need to hassle with user-data)

Adding it is as simple as this:

PhysixComponentAwareContactListener contactListener = new PhysixComponentAwareContactListener();
physixSystem.getWorld().setContactListener(contactListener);
contactListener.addListener(TriggerComponent.class, new TriggerListener());

PhysixContactListener / PhysixContactAdapter

Just as with Box2D, there is a listener Interface:

public interface PhysixContactListener {
    void beginContact(PhysixContact contact);
    void endContact(PhysixContact contact);
    void preSolve(PhysixContact contact, Manifold oldManifold);
    void postSolve(PhysixContact contact, ContactImpulse impulse);
}

The only difference is that you get a PhysixContact instead of a Contact object.

PhysixContactAdapter just implements all methods from PhysixContactListener, so you just need to override the ones you actually need.

PhysixContact

PhysixContact differs from Contact a bit:

  • In Contact you had the fixtures "A" and "B", but no idea which is which.
  • In `PhysixContact you get the fixtures "My" and "Other".
    • "My" is always the fixture which has the specified component class.
    • "Other" is the other fixture, but it might also have the specified component class!

All methods from Contact are proxied by PhysixContact. Plus you get a couple of getMy* and getOther* Methods. Check out your code-completion.