Rotating objects with jbullet-jme

Here's my problem. I have a gamestate in which I have some PhysicsNodes. I would want the player to be able to rotate an object, that implements physics. In example if a ball falls on the object, the player must be able to rotate the underlying object to balance the ball, so that it won't fall. In simple terms, this means that the player rotates the level and tries to balance it so that he/she can move the ball to the finish line. (Like kororinpa on the wii).



I've tried to accomplish this with the following code in the gamestate (I guess some variable/method names are a bit off-putting, but try to bear with me):


      pSpace = PhysicsSpace
            .getPhysicsSpace(PhysicsSpace.BroadphaseTypes.AXIS_SWEEP_3);

      KeyBindingManager.getKeyBindingManager().add("rotateLevelNorth",
            KeyInput.KEY_U);
      KeyBindingManager.getKeyBindingManager().add("rotateLevelSouth",
            KeyInput.KEY_J);
      KeyBindingManager.getKeyBindingManager().add("rotateLevelWest",
            KeyInput.KEY_H);
      KeyBindingManager.getKeyBindingManager().add("rotateLevelEast",
            KeyInput.KEY_K);

      createSkyBox();

      Sphere sphere = new Sphere("sphere", 20, 20, 0.5f);
      sphere.setModelBound(new BoundingSphere());
      sphere.updateModelBound();
      PhysicsNode pSphere = new PhysicsNode(sphere,
            CollisionShape.ShapeTypes.SPHERE);
      pSphere.setLocalTranslation(new Vector3f(-15.0f, 0.0f, -12.5f));
      pSphere.setRestitution(0.3f);
      pSpace.add(pSphere);
      rootNode.attachChild(pSphere);
      pSphere.updateRenderState();
      
       ObjToJme converter = new ObjToJme();
       try {
       URL objFile = SandBoxGameState.class.getClassLoader().getResource(
       "models/level1.obj");
       converter.setProperty("mtllib", objFile);
       converter.setProperty("texdir", objFile);
       ByteArrayOutputStream BO = new ByteArrayOutputStream();
       converter.convert(objFile.openStream(), BO);
       TriMesh level = (TriMesh) BinaryImporter.getInstance().load(
       new ByteArrayInputStream(BO.toByteArray()));
       level.setModelBound(new BoundingBox());
       level.updateModelBound();
       level.setLocalScale(7.0f);
       pLevel = new PhysicsNode(level, CollisionShape.ShapeTypes.MESH, 0);
       pLevel.setLocalTranslation(new Vector3f(0.0f, -5.0f, 0.0f));
       pLevel.setRestitution(0.3f);
       pSpace.add(pLevel);
       rootNode.attachChild(pLevel);
       pLevel.updateRenderState();
       } catch (Exception e) {
       // just don't create the object :)
       }


In the state's update method I try to rotate the "level" object:

if (KeyBindingManager.getKeyBindingManager().isValidCommand(
               "rotateLevelNorth", true)) {
            if (xAngle == 360.0f || xAngle == 0.0f) {
               xAngle = 0.1f;
            } else {
               xAngle = xAngle + 0.1f;
            }
            pLevel.setLocalRotation(rotateY().mult(rotateX()));
         }
         if (KeyBindingManager.getKeyBindingManager().isValidCommand(
               "rotateLevelSouth", true)) {
            if (xAngle == -360.0f || xAngle == 0.0f) {
               xAngle = -0.1f;
            } else {
               xAngle = xAngle - 0.1f;
            }
            pLevel.setLocalRotation(rotateY().mult(rotateX()));
         }
         if (KeyBindingManager.getKeyBindingManager().isValidCommand(
               "rotateLevelWest", true)) {
            if (yAngle == -360.0f || yAngle == 0.0f) {
               yAngle = -0.1f;
            } else {
               yAngle = yAngle - 0.1f;
            }
            pLevel.setLocalRotation(rotateY().mult(rotateX()));
         }
         if (KeyBindingManager.getKeyBindingManager().isValidCommand(
               "rotateLevelEast", true)) {
            if (yAngle == 360.0f || yAngle == 0.0f) {
               yAngle = 0.1f;
            } else {
               yAngle = yAngle + 0.1f;
            }
            pLevel.setLocalRotation(rotateY().mult(rotateX()));
         }
super.update(tpf);
         pSpace.update(tpf);



Here's the rotateY() and rotateX() methods:

private Quaternion rotateY() {
      Quaternion pitch = new Quaternion();
      pitch.fromAngleAxis(FastMath.PI * xAngle / 180.0f, new Vector3f(0.0f,
            0.0f, -1.0f));
      return pitch;
   }

   private Quaternion rotateX() {
      Quaternion pitch = new Quaternion();
      pitch.fromAngleAxis(FastMath.PI * yAngle / 180.0f, new Vector3f(1.0f,
            0.0f, 0.0f));
      return pitch;
   }



The problem I have is that when I rotate the level object too much (i.e. 60 degrees), the ball (and other physics objects) start falling "through" the object in some places on the surface of the "level". When I turn it back to the original position, it starts working again. Also when the objects fall through, sometimes they freeze in the air. Sometimes they even freeze when they just touch the level object. Even if I haven't moved the level, the ball just spawns on top of it and randomly freezes. I'm pretty frustrated because it seems so random, I may have taken a wrong approach completely?

I'm using jmonkeyengine 2.0 from trunk and jbullet-jme 0.9.5.

The problem is that you use a static collision shape (mass=0) and move it. That is not possible, no forces can be computed without mass and static objects should generally be just that, static :slight_smile:

If you manage to download and build jbullet-jme from trunk, you can set a mass for your floor collision shape and setKinematic(true) to make it a kinematic node, then it should work.

Thanks for the lighting fast reply, I think I get it now… Can't try it right away but I think I'll try to fix this tonight when I get back home :slight_smile:

I also uploaded v0.9.6 now, including kinematic physics nodes and a debug view.

normen said:

I also uploaded v0.9.6 now, including kinematic physics nodes and a debug view.


I updated to v0.9.6, made the changes and it fixed the problem! Thanks!