Time for action – you are the CubeChaser

Let's do something more interactive than just look at rotating cubes. Can you write code that lets you chase one of the cubes? By chase we mean, if the camera moves closer than 10 WU to this cube, the cube should move away from the camera.

  1. Make another copy of the BasicGame object's Main.java template.
  2. Rename the copy to CubeChaser.java. Remember to also refactor the first line of the main() method to the following:
    CubeChaser app = new CubeChaser();
  3. Delete the blue cube and copy the myBox() convenience method from one of the previous target picking examples. Don't forget to copy the mesh class field.
  4. Add a makeCubes(40); call to the simpleInitApp() method and fill the scene with 40 randomly positioned and randomly colored cubes. Use the built-in method FastMath.nextRandomInt(min,max) (from com.jme3.math) to generate random coordinates in the interval between min and max.
    private void makeCubes(int number) {
      for (int i = 0; i < number; i++) {
        // randomize 3D coordinates
        Vector3f loc = new Vector3f(
          FastMath.nextRandomInt(-20, 20),
          FastMath.nextRandomInt(-20, 20),
          FastMath.nextRandomInt(-20, 20));
        rootNode.attachChild(
          myBox("Cube" + i, loc, ColorRGBA.randomColor()));
      }
    }
  5. Create a white cube geometry, scaredCube, as a class field, and position it in the origin.
    private Geometry scaredCube;
    ...
    public void simpleInitApp() {
      makeCubes(40);
      scaredCube = myBox("Scared Cube", Vector3f.ZERO, ColorRGBA.White);
      rootNode.attachChild(scaredCube);
    }

    How would you write code that constantly monitors the distance between the camera location and the location of the scaredCube object? You write these kinds of tests in the simpleUpdate(float tpf) method.

  6. Use the vector1.distance(vector2) method for the distance test. You get current object coordinates by calling the cam.getLocation() and cube.getLocalTranslation() methods.
    public void simpleUpdate(float tpf) {
      System.out.println("Distance: "+
        cam.getLocation().distance(scaredCube.getLocalTranslation()));
    }
  7. Modify this code so that it tests whether the distance is less than 10 WU. If yes, then move the scared cube away from you, that is, in the direction that the camera is facing.
    public void simpleUpdate(float tpf) {
      ...
      if (cam.getLocation().distance(scaredCube.getLocalTranslation()) < 10) {
        scaredCube.move(cam.getDirection());
      }
    }

Run the class and use the W, A, S, and D keys and the mouse to navigate through the cube-filled scene. Keep an eye on the white cube!

Tip

If you feel you are moving too slow, you can speed up the default camera. Add the following command somewhere in the simpleInitApp() method:

flyCam.setMoveSpeed(100f);

What just happened?

When you run this class you see that the simpleUpdate() method prints a lot of output to the console. The current camera location and the cube location are polled in every frame, and their distance is recalculated and printed. The simpleUpdate() method ensures that your test always returns the latest results, even while you and the scared cube are moving wildly through the scene.

If you back away and move around the cube—sneak up on it from behind, so to speak—you can chase it back into the cluster of cubes. Just like the camera location, the camera direction inside the simpleUpdate() method returns an updated value every frame. The vector points in the new direction while you navigate the camera around the cube, so that you can chase the cube back.

The simpleUpdate() method is one way to hook code directly into the main loop. Everything in this method is executed repeatedly, as fast as possible, as long as the game runs. (Hint: Be careful when creating new objects here!) Just like the simpleInitApp() method, you never call the simpleUpdate() method yourself. You only implement the method body, and jMonkeyEngine takes care of executing it.