JBullet NullPointer on step simulation in separate thread

184 Views Asked by At

I have a setup in my game where physics are updated in a separate thread with an implementation as follows

Physics Processor (Physics Thread)

public class PhysicsProcessor extends Runnable {
    private DynamicsWorld world;

    public PhysicsProcessor() {
        /* basic dynamics world setup with dvbt broadphase :P */
    }

    public synchronized getDynamicsWorld() { return world; }

    @Override
    public void run() {
        /* update time */

        //update phyics
        getDynamicsWorld().stepSimulation(/* delta time */);
    }
}

Example Object Creation In Main Thread

myPhysicsProcessor.getDynamicsWorld.addRigidBody(/* some rigid body created here */);

The problem is that when the game runs I occasionally get a null pointer exception in the separate thread on "stepSimulation", which was caused by setAabb in my dbvt broadphase.

Does anyone have any suggestions on what I can do to prevent this exception, or how to work around it?

1

There are 1 best solutions below

0
On

You could make the world final from the looks of it. Then that would show you the futility of synchronizing the access:

public class PhysicsProcessor extends Runnable {
    private final DynamicsWorld world;

    public synchronized DynamicsWorld getDynamicsWorld() { return world; } //why sync? it can't change
}

You see, when you do: myPhysicsProcessor.getDynamicsWorld().addRigidBody(...) the synchronization stops after the getDynamicsWorld() returns. So addRigidBody(...) is called outside of the safe synchronized context.

No, what you want to do is ensure that it is always used within a sync block:

@Override
public void run() {
    //update physics
    synchronized(this) {
      world.stepSimulation(/* delta time */);
    }
}

public void addBody(/*args here*/) {
    synchronized(this) {
      world.addRigidBody(/*args here*/);
    }
}

Now that's OK for one method, but if you find yourself wanting to do lots of methods of DynamicsWorld outside the runner in this way, or just want another choice, then this one requires no syncing:

public interface IWorldRunable {    
  void run(DynamicsWorld world);    
}    

public class PhysicsProcessor extends Runnable {
    private final DynamicsWorld world;
    private final ConcurrentLinkedQueue<IWorldRunable> worldRunables = ConcurrentLinkedQueue<IWorldRunable>();

    public PhysicsProcessor() {
        /* basic dynamics world setup with dvbt broadphase :P */
    }

    @Override
    public void run() {
        /* update time */

        //run runables on world
        for(IWorldRunable runable : worldRunables)
          runable.run(world);

        //clear runables
        worldRunables.clear();

        //update phyics
        world.stepSimulation(/* delta time */);
    }

    public void do(IWorldRunable runnable) {
        worldRunables.add(runnable);
    }
}

Then you would do this, to add a body:

myPhysicsProcessor.do(new IWorldRunable(){      
  @Override
  public void run(DynamicsWorld world){
     world.addRigidBody(...);
  }
});

It will get executed before the next stepSimulation on the same thread as that, so no thread worries.