My Target: Moving Boxes inside a 3D Environment

Hello everybody!



I want to program an application where small boxes move inside a 3D-Scene

These boxes should:

  • be visible
  • there should be gravity and collision detection enabled for them
  • it should be possible to move them continously (not by keyboard or mouseinput - I want that they are getting steered by random numbers which are thrown in my program! For example: Number 1: meens moving the box positively on the x axis, Number 2: move the box negatively on x axis etc.)
  • I want to watch them from a third person perspective (i dont want to be “inside the box”)



    I am a complete newbie in using the JMonkeyEngine and as a first step I took the code example from the collision detection beginner tutorial as base.



    [java]import com.jme3.app.SimpleApplication;

    import com.jme3.asset.plugins.ZipLocator;

    import com.jme3.bullet.BulletAppState;

    import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;

    import com.jme3.bullet.collision.shapes.CollisionShape;

    import com.jme3.bullet.control.CharacterControl;

    import com.jme3.bullet.control.RigidBodyControl;

    import com.jme3.bullet.util.CollisionShapeFactory;

    import com.jme3.input.KeyInput;

    import com.jme3.input.controls.ActionListener;

    import com.jme3.input.controls.KeyTrigger;

    import com.jme3.light.AmbientLight;

    import com.jme3.light.DirectionalLight;

    import com.jme3.material.Material;

    import com.jme3.math.ColorRGBA;

    import com.jme3.math.Vector3f;

    import com.jme3.scene.Geometry;

    import com.jme3.scene.Node;

    import com.jme3.scene.Spatial;

    import com.jme3.scene.shape.Box;





    public class SEMain extends SimpleApplication

    implements ActionListener {



    private Spatial sceneModel;

    private BulletAppState bulletAppState;

    private RigidBodyControl landscape;



    private boolean move_box_x_pos = false, move_box_x_neg = false, move_box_z_pos = false, move_box_z_neg = false;

    private Geometry my_box;



    public static void main(String[] args) {

    SEMain app = new SEMain();

    app.start();

    }



    public void simpleInitApp() {

    bulletAppState = new BulletAppState();

    stateManager.attach(bulletAppState);

    //bulletAppState.getPhysicsSpace().enableDebug(assetManager);



    viewPort.setBackgroundColor(new ColorRGBA(0.7f, 0.8f, 1f, 1f));

    flyCam.setMoveSpeed(100);

    setUpKeys();

    setUpLight();



    // We load the scene from the zip file and adjust its size.

    assetManager.registerLocator(“town.zip”, ZipLocator.class);

    sceneModel = assetManager.loadModel(“main.scene”);

    sceneModel.setLocalScale(2f);





    CollisionShape sceneShape =

    CollisionShapeFactory.createMeshShape((Node) sceneModel);

    landscape = new RigidBodyControl(sceneShape, 0);

    sceneModel.addControl(landscape);



    Box b = new Box( new Vector3f(4,10,4), 2,2,2);

    my_box = new Geometry(“mybox”,b);

    Material m = new Material(assetManager,“Common/MatDefs/Misc/Unshaded.j3md”);

    m.setColor(“Color”, ColorRGBA.Green);

    my_box.setMaterial(m);



    rootNode.attachChild(sceneModel);

    rootNode.attachChild(my_box);



    bulletAppState.getPhysicsSpace().add(landscape);

    //bulletAppState.getPhysicsSpace().add(my_box); //adding mybox to physicsspace… does not work (causes NullpointerException)

    }



    private void setUpLight() {

    AmbientLight al = new AmbientLight();

    al.setColor(ColorRGBA.White.mult(1.3f));

    rootNode.addLight(al);



    DirectionalLight dl = new DirectionalLight();

    dl.setColor(ColorRGBA.White);

    dl.setDirection(new Vector3f(2.8f, -2.8f, -2.8f).normalizeLocal());

    rootNode.addLight(dl);

    }



    /** We over-write some navigational key mappings here, so we can
  • add physics-controlled walking and jumping: /

    private void setUpKeys() {

    //Input mappings for my purposes

    inputManager.addMapping("move_box_x_neg", new KeyTrigger(KeyInput.KEY_F));

    inputManager.addMapping("move_box_x_pos", new KeyTrigger(KeyInput.KEY_H));

    inputManager.addMapping("move_box_z_pos", new KeyTrigger(KeyInput.KEY_T));

    inputManager.addMapping("move_box_z_neg", new KeyTrigger(KeyInput.KEY_G));

    inputManager.addListener(this, "move_box_x_pos");

    inputManager.addListener(this, "move_box_x_neg");

    inputManager.addListener(this, "move_box_z_pos");

    inputManager.addListener(this, "move_box_z_neg");

    }



    //save the user input in boolean variables (analogously to the tutorial)

    public void onAction(String binding, boolean value, float tpf) {

    if (binding.equals("move_box_x_pos")) {

    move_box_x_pos = value;

    } else if (binding.equals("move_box_x_neg")) {

    move_box_x_neg = value;

    } else if (binding.equals("move_box_z_pos")) {

    move_box_z_pos = value;

    } else if (binding.equals("move_box_z_neg")) {

    move_box_z_neg = value;

    }

    }





    @Override

    public void simpleUpdate(float tpf) {



    Vector3f position = ((Box)my_box.getMesh()).getCenter(); // getting the center of my box



    //add a vector to the center position yealding the "new position"

    if (move_box_x_pos) { position.addLocal(new Vector3f(-10
    tpf,0,0)); }

    if (move_box_x_neg) { position.addLocal(new Vector3f(10tpf,0,0)); }

    if (move_box_z_pos) { position.addLocal(new Vector3f(0,0,10
    tpf)); }

    if (move_box_z_neg) { position.addLocal(new Vector3f(0,0,-10*tpf)); }



    Box b2 = new Box(position,2,2,2); //create new box at the "new position"

    my_box.setMesh(b2); //set the mesh



    System.out.println("Cam:"+cam.getLocation());

    System.out.println("my_box:"+((Box)my_box.getMesh()).getCenter());

    }

    }[/java]



    I did the following steps:
  • I removed the “CharacterControl player” things from the code and added a Geometry “my_box” to the scene
  • I modified the steering operations to my purposes



    If one executes thie code one will get a green box in the (town-)scene which can be steered by the TFGH-Buttons (and the cam by WASD)



    As you can see in the update-function I steer the box by
  • getting the Mesh of the Geometry,
  • getting the Meshs position
  • constructing a new Mesh with another position
  • setting the new Mesh as Mesh of the geometry



    Now my questions:
  • Is this the right way I am going for my purposes?
  • How can I enable collision detection and physics for this box? (//bulletAppState.getPhysicsSpace().add(my_box); //adding mybox to physicsspace… does not work (causes NullpointerException)
  • How can I steer it with “random numbers”? (Binding keyinput to strings using input manager is nice… but i think i cannot use that technique in this case)
  • my_box should also have some more “intelligence”… for example the my_box shell be able to read color values and light values from the scene. I think i could easily subclass the geometry class by a “MyBox” class and putting the intelligence there… is that a recommended usage of the engine?



    Thanks in advance.

Except that you don’t need to create a new mesh each frame basically this is the right way but if you have to control physics objects continuously with collision (as in them colliding) then use setLinearVelocity or the CharacterControl. If you only need the other objects to be pushed by the moved objects, use kinematic mode and setLocation as you do. Also check out the tutorials, they explain moving stuff and a host of other things.