libGDX + box2D – how to avoid crashes?

Some people don’t use box2D with libGDX because they think it’s unstable. The truth is, it isn’t. It’s stable as a rock but you have to remember it is written in native code. I had two reasons box2D crashed my games, let’s see how to avoid both.

Box2D bodies in my upcoming platformer

Don’t touch dead bodies

This is really important. When you destroy a body because you no longer need it you have to make sure you also nullify all references to it. It’s easy to push reference to Body to some method and then forget you had saved it for later and it is referenced in some object – only to be used in the future when the body is already destroyed somewhere else. In best case scenario you will change another body (that reuses the pointer of the original body) but in most cases you will crash your game with some horrible, hard to understand crash log.

The solution is – NEVER use reference to a body in your methods and store your Body in a single object. Instead put your body as a field of a single class and always when you destroy it set it to null afterwards:

1
2
3
4
5
6
7
8
9
10
11
12
class MyPhysicsActor extends Actor
{
    Body body;
    float speed; // or some other additions to Scene2D actors
 
    // some method to destroy the body
    void destroyBody()
    {
       world.destroyBody(body);
       body = null; // that way you lose the only reference to the body as you should - it has been destroyed
    }
}
class MyPhysicsActor extends Actor
{
    Body body;
    float speed; // or some other additions to Scene2D actors

    // some method to destroy the body
    void destroyBody()
    {
       world.destroyBody(body);
       body = null; // that way you lose the only reference to the body as you should - it has been destroyed
    }
}

Make sure you always use your MyPhysicsActor when you want to reference the body, not the Body object itself and everything will be fine.

Don’t change me while I tick

Another common cause of problems is when you invoke some methods in postSolve/preSolve and similar box2D internal functions and that method modifyes the box2d objects in some way – that crashes your game, but this time fortunately with a much easier to understand error message. Anyway, to avoid it use actions that are executed outside of the box2D functions – I have something like that in my games:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// fields
Array<Actor> toDoElement = new Array<Actor>();
Array<String> toDo = new Array<String>();
 
// in the update method invoked each frame
 
phys.tick(); // this is where box2D ticks
 
int size = toDo.size;
for(int i=0; i<size; i++)
    execute(toDoElement.get(i), toDo.get(i)); // this executes my action
 
if(size>0)
{
    toDo.removeRange(0, size-1);
    toDoElement.removeRange(0, size-1);
}
 
public void addToDo(String name, MaImage element)
{
    toDo.add(name);
    toDoElement.add(element);
}
 
// example actions that might be invoked in postSolve:
addToDo("removeBody", myActorWithBody);
addToDo("reduceSpeed", myActorWithBody);
addToDo("clearTheWorld", null);
// fields
Array<Actor> toDoElement = new Array<Actor>();
Array<String> toDo = new Array<String>();

// in the update method invoked each frame

phys.tick(); // this is where box2D ticks

int size = toDo.size;
for(int i=0; i<size; i++)
    execute(toDoElement.get(i), toDo.get(i)); // this executes my action

if(size>0)
{
    toDo.removeRange(0, size-1);
    toDoElement.removeRange(0, size-1);
}

public void addToDo(String name, MaImage element)
{
    toDo.add(name);
    toDoElement.add(element);
}

// example actions that might be invoked in postSolve:
addToDo("removeBody", myActorWithBody);
addToDo("reduceSpeed", myActorWithBody);
addToDo("clearTheWorld", null);

So the actions in my code are posponed until the tick is finished when it’s safe to execute them. I use the action also for things unrelated to box2D.

You may also like...