Upon request I’ve created a test showing how to work with the classes I posted.
I’ve also placed the camera system in a jar, which can be downloaded here.
/*
* Copyright (c) 2003-2004, jMonkeyEngine - Mojo Monkey Coding All rights
* reserved. Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer. Redistributions in binary
* form must reproduce the above copyright notice, this list of conditions and
* the following disclaimer in the documentation and/or other materials provided
* with the distribution. Neither the name of the Mojo Monkey Coding, jME,
* jMonkey Engine, nor the names of its contributors may be used to endorse or
* promote products derived from this software without specific prior written
* permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package test;
import java.util.ArrayList;
import com.jme.app.SimpleGame;
import com.jme.math.FastMath;
import com.jme.math.Matrix3f;
import com.jme.math.Vector3f;
import com.jme.scene.BillboardNode;
import com.jme.scene.Controller;
import com.jme.scene.Node;
import com.jme.scene.shape.Box;
import com.jme.scene.shape.Quad;
import com.jme.scene.shape.Sphere;
import camerasys.CameraHandler;
/**
* @author Per Thulin
*/
public class TestCameraSystem extends SimpleGame {
// The sphere moving back and forth.
private Sphere player;
// The box that makes out the ground.
private Box ground;
// Shows that Nodes also can be passed as targets.
private Node complex;
// The same applies to BillboardNodes.
private BillboardNode billboard;
// Used in <code>ThirdPersonHandler</code> to swap between targets.
private ArrayList targets;
// Makes the camera follow after and face our target.
private CameraHandler cameraHandler;
protected void simpleInitGame() {
display.setTitle("Test Camera System | Wheel = zoom | S = swap target | + & - = vertical displacement");
targets = new ArrayList();
initPlayer();
initComplexTarget();
initBillboardTarget();
initGround();
initCamera();
initInput();
}
private void initPlayer() {
player = new Sphere("Player", 40, 40, 3);
rootNode.attachChild(player);
rootNode.addController(new PlayerMover());
targets.add(player);
}
private void initComplexTarget() {
complex = new Node("Complex Target");
complex.setLocalTranslation(new Vector3f(-170, 20, 0));
complex.addController(new ComplexMover());
Box b1 = new Box("Box 1", new Vector3f(), 10, 10, 10);
b1.setLocalTranslation(new Vector3f(0, 0, 0));
complex.attachChild(b1);
Box b2 = new Box("Box 2", new Vector3f(), 10, 1, 5);
b2.setLocalTranslation(new Vector3f(0, 30f, 0));
complex.attachChild(b2);
Sphere s1 = new Sphere("Sphere 1", 10, 10, 10);
s1.setLocalTranslation(new Vector3f(0, 15f, 0));
complex.attachChild(s1);
rootNode.attachChild(complex);
targets.add(complex);
}
private void initBillboardTarget() {
billboard = new BillboardNode("Billboard Target");
billboard.setLocalTranslation(new Vector3f(150, 30, 0));
billboard.attachChild(new Quad("Quad", 10, 10));
rootNode.attachChild(billboard);
targets.add(billboard);
}
private void initGround() {
ground = new Box("Ground", new Vector3f(), 150, 1, 150);
ground.setLocalTranslation(new Vector3f(0, -5f, 0));
rootNode.attachChild(ground);
targets.add(ground);
}
private void initCamera() {
// Theta and phi is the start angles. If theta = 180 degrees the
// billboard node gets screwed up. Why? I don't know :P
float theta = 175 * FastMath.DEG_TO_RAD;
float phi = 50 * FastMath.DEG_TO_RAD;
// 200 = distance to the target.
cameraHandler = new CameraHandler(theta, phi, 200);
cameraHandler.setTarget(player);
}
private void initInput() {
input = new ThirdPersonHandler(cameraHandler, targets);
}
public static void main(String[] args) {
TestCameraSystem app = new TestCameraSystem();
app.setDialogBehaviour(TestCameraSystem.ALWAYS_SHOW_PROPS_DIALOG);
app.start();
}
/**
* A controller that makes the sphere move back and forth.
*
* @author Per Thulin
*/
private class PlayerMover extends Controller {
private float counter;
public void update(float tpf) {
counter += tpf;
float z = FastMath.sin(counter) * 100f;
player.getLocalTranslation().z = z;
}
}
/**
* A controller that makes the complex target rotate and move up and down.
*
* @author Per Thulin
*/
private class ComplexMover extends Controller {
// temporary variables for rotation
private final Vector3f tempVa = new Vector3f();
private final Matrix3f incr = new Matrix3f();
private final Matrix3f tempMa = new Matrix3f();
private final Matrix3f tempMb = new Matrix3f();
private float counter;
public void update(float tpf) {
counter += tpf;
float y = 50 + FastMath.sin(counter) * 100f;
complex.getLocalTranslation().y = y;
incr.loadIdentity();
incr.fromAxisAngle(complex.getLocalRotation().getRotationColumn(1,
tempVa), 5 * tpf);
complex.getLocalRotation().fromRotationMatrix(
incr.mult(complex.getLocalRotation().toRotationMatrix(tempMa),
tempMb));
complex.getLocalRotation().normalize();
}
}
}
/*
* Copyright (c) 2003-2004, jMonkeyEngine - Mojo Monkey Coding All rights
* reserved. Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer. Redistributions in binary
* form must reproduce the above copyright notice, this list of conditions and
* the following disclaimer in the documentation and/or other materials provided
* with the distribution. Neither the name of the Mojo Monkey Coding, jME,
* jMonkey Engine, nor the names of its contributors may be used to endorse or
* promote products derived from this software without specific prior written
* permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package test;
import java.util.ArrayList;
import com.jme.input.InputHandler;
import com.jme.input.InputSystem;
import com.jme.input.KeyBindingManager;
import com.jme.input.KeyInput;
import com.jme.input.RelativeMouse;
import com.jme.scene.Spatial;
import camerasys.CameraHandler;
import camerasys.SphericalMouseLook;
/**
* @author Per Thulin
*/
public class ThirdPersonHandler extends InputHandler {
private SphericalMouseLook mouseLook;
private CameraHandler cameraHandler;
private ArrayList targets;
private int targetNumber;
public ThirdPersonHandler(CameraHandler cameraHandler, ArrayList targets) {
this.cameraHandler = cameraHandler;
this.targets = targets;
targetNumber = 0;
initKeyboard();
initMouse();
}
private void initKeyboard() {
keyboard = KeyBindingManager.getKeyBindingManager();
keyboard.setKeyInput(InputSystem.getKeyInput());
keyboard.set("increase_y_displacement", KeyInput.KEY_ADD);
keyboard.set("decrease_y_displacement", KeyInput.KEY_SUBTRACT);
keyboard.set("swap_target", KeyInput.KEY_S);
setKeyBindingManager(keyboard);
}
private void initMouse() {
mouse = new RelativeMouse("Mouse Input");
mouse.setMouseInput(InputSystem.getMouseInput());
setMouse(mouse);
mouseLook = new SphericalMouseLook(mouse, cameraHandler);
addAction(mouseLook);
}
public void update(float time) {
super.update(time);
if(keyboard.isValidCommand("increase_y_displacement")) {
cameraHandler.getDisplacement().y += time * 100;
}
if(keyboard.isValidCommand("decrease_y_displacement")) {
cameraHandler.getDisplacement().y -= time * 100;
}
if(keyboard.isValidCommand("swap_target", false)) {
targetNumber++;
if (targetNumber >= targets.size()) targetNumber = 0;
cameraHandler.setTarget((Spatial) targets.get(targetNumber));
}
cameraHandler.update(time);
}
}