Right @mifth, My fault. I feel so stupid.
Here is a new version, but rotation is a bit awkward when close to the top/bottom. You would think the camera would go down, but this would actually rotate your Z axis.
With this version, you have a turntable that you can look over or below… without tilting your head.
Is that what you are looking for ?
[java]
package mygame;
import com.jme3.app.Application;
import com.jme3.app.state.AbstractAppState;
import com.jme3.app.state.AppStateManager;
import com.jme3.input.InputManager;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.AnalogListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseAxisTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
import com.jme3.scene.CameraNode;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.CameraControl;
/**
- A camera that fly around the specified object
-
-
@author jeanpierre
*/
public class FlyAroundAppState extends AbstractAppState implements ActionListener, AnalogListener {
protected boolean dragToRotate, dragged;
protected Camera cam;
protected Spatial target;
protected Node rotH,rotV;
protected CameraNode translate;
protected boolean up, down, left, right, fwd, bkwd, clicked;
protected float linSpeed, rotSpeed;
protected InputManager inputManager;
/**
- Builds a new fly-around camera
*/
public FlyAroundAppState() {
rotH = new Node(“orbitH”);
rotV = new Node(“orbitV”);
rotH.attachChild(rotV);
dragToRotate = dragged = false;
}
@Override
public void initialize(AppStateManager stateManager, Application app) {
super.initialize(stateManager, app);
cam = app.getCamera();
translate = new CameraNode(“dolly”, cam);
translate.setControlDir(CameraControl.ControlDirection.SpatialToCamera);
rotV.attachChild(translate);
up = down = left = right = false;
linSpeed = 5;
rotSpeed = 0.5f;
inputManager = app.getInputManager();
initInputAZERTY();
initInputMouse();
inputManager.setCursorVisible(dragToRotate);
}
/**
- Sets the move speed of the camera
-
-
@param lin the linear speed
-
@param ang the angular speed
*/
public void setSpeed(float lin, float ang) {
linSpeed = lin;
rotSpeed = ang;
}
/**
- Attaches the camera to the rootnode. MUST be used!
-
-
@param rootNode the root node
*/
public void setRootNode(Node rootNode) {
rootNode.attachChild(rotH);
}
/**
- Sets the distance of the camera to the target
-
-
@param d the distance to set
*/
public void setDistance(float d) {
translate.setLocalTranslation(0, 0, -d);
}
/**
-
Sets the target to turn around
-
-
@param to the spatial to turn around or null for free-flight
*/
public void setTarget(Spatial to) {
if (to != null) {
rotH.setLocalTranslation(cam.getLocation());
translate.setLocalTranslation(Vector3f.ZERO);
}
if (to != null && target != to) {
float d = rotH.getWorldTranslation().distance(to.getWorldTranslation());
// rotH.lookAt(to.getWorldTranslation(), cam.getUp());
Vector3f dir = to.getWorldTranslation().subtract(rotH.getWorldTranslation()).normalizeLocal();
float elev = dir.angleBetween(Vector3f.UNIT_Y) - FastMath.HALF_PI;
dir.y = 0;
dir.normalizeLocal();
float rot = dir.angleBetween(Vector3f.UNIT_Z);
rotH.setLocalRotation(new Quaternion(new float[]{0,rot,0}));
rotV.setLocalRotation(new Quaternion(new float[]{elev,0,0}));
rotH.setLocalTranslation(to.getWorldTranslation());
translate.setLocalTranslation(0, 0, -d);
target = to;
} else {
rotH.setLocalTranslation(cam.getLocation());
translate.setLocalTranslation(Vector3f.ZERO);
target = null;
}
}
/**
- Sets the camera to control
-
-
@param cam the camera to control
*/
public void setCamera(Camera cam) {
this.cam = cam;
}
/**
- Set if drag to rotate mode is enabled.
-
- When true, the user must hold the mouse button and drag over the screen to
- rotate the camera, and the cursor is visible until dragged. Otherwise, the
- cursor is invisible at all times and holding the mouse button is not needed
- to rotate the camera. This feature is disabled by default.
-
-
@param dragToRotate True if drag to rotate mode is enabled.
*/
public void setDragToRotate(boolean dragToRotate) {
this.dragToRotate = dragToRotate;
if (inputManager != null) {
inputManager.setCursorVisible(dragToRotate);
}
}
/**
-
@return true iff the latest click has moved the camera
*/
public boolean hasDragged() {
return dragged;
}
/**
-
@return If drag to rotate feature is enabled.
-
-
@see FlyAroundAppState#setDragToRotate(boolean)
*/
public boolean isDragToRotate() {
return dragToRotate;
}
@Override
public void update(float tpf) {
float speed;
if (target == null) {
// no anchor, move the rotate point
speed = -rotSpeed; // rotation inverted when no target
if (fwd) {
rotH.move(cam.getDirection().mult(tpf * linSpeed));
}
if (bkwd) {
rotH.move(cam.getDirection().mult(tpf * -linSpeed));
}
} else {
// anchor is set, move around it
speed = +rotSpeed;
if (fwd) {
translate.move(0, 0, tpf * linSpeed);
}
if (bkwd) {
translate.move(0, 0, tpf * -linSpeed);
}
}
if (up) {
rotV.rotate(tpf * speed, 0, 0);
}
if (down) {
rotV.rotate(tpf * -speed, 0, 0);
}
if (cam.getUp().dot(Vector3f.UNIT_Y) < 0)
speed = - speed;
if (left) {
rotH.rotate(0, tpf * -speed, 0);
}
if (right) {
rotH.rotate(0, tpf * speed, 0);
}
} // update(tpf)
public void onAction(String name, boolean isPressed, float tpf) {
if ("Click".equals(name)) {
clicked = isPressed;
if (dragToRotate) {
inputManager.setCursorVisible(!clicked);
if (clicked) {
dragged = false;
}
}
}
if ("Up".equals(name)) {
up = isPressed;
} else if ("Down".equals(name)) {
down = isPressed;
} else if ("Left".equals(name)) {
left = isPressed;
} else if ("Right".equals(name)) {
right = isPressed;
} else if ("Fwd".equals(name)) {
fwd = isPressed;
} else if ("Bkwd".equals(name)) {
bkwd = isPressed;
}
} // onAction(…)
protected void initInputAZERTY() {
inputManager.addMapping("Up", new KeyTrigger(KeyInput.KEY_Z));
inputManager.addMapping("Down", new KeyTrigger(KeyInput.KEY_S));
inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_Q));
inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_D));
inputManager.addMapping("Fwd", new KeyTrigger(KeyInput.KEY_PGUP));
inputManager.addMapping("Bkwd", new KeyTrigger(KeyInput.KEY_PGDN));
inputManager.addListener(this, "Up", "Down", "Left", "Right", "Fwd", "Bkwd");
}
protected void initInputQWERTY() {
inputManager.addMapping("Up", new KeyTrigger(KeyInput.KEY_W));
inputManager.addMapping("Down", new KeyTrigger(KeyInput.KEY_S));
inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_A));
inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_D));
inputManager.addMapping("Fwd", new KeyTrigger(KeyInput.KEY_PGUP));
inputManager.addMapping("Bkwd", new KeyTrigger(KeyInput.KEY_PGDN));
inputManager.addListener(this, "Up", "Down", "Left", "Right", "Fwd", "Bkwd");
}
protected void initInputMouse() {
inputManager.addMapping("UpM", new MouseAxisTrigger(MouseInput.AXIS_Y, false));
inputManager.addMapping("DownM", new MouseAxisTrigger(MouseInput.AXIS_Y, true));
inputManager.addMapping("LeftM", new MouseAxisTrigger(MouseInput.AXIS_X, true));
inputManager.addMapping("RightM", new MouseAxisTrigger(MouseInput.AXIS_X, false));
inputManager.addMapping("FwdM", new MouseAxisTrigger(MouseInput.AXIS_WHEEL, false));
inputManager.addMapping("BkwM", new MouseAxisTrigger(MouseInput.AXIS_WHEEL, true));
inputManager.addMapping("Click", new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
inputManager.addListener(this, "UpM", "DownM", "LeftM", "RightM", "FwdM", "BkwM", "Click");
}
public void onAnalog(String name, float value, float tpf) {
float speed;
if (target == null) {
// no anchor, move the rotate point
speed = -rotSpeed * 100 * value; // rotation inverted when no target
if ("FwdM".equals(name)) {
rotH.move(cam.getDirection().mult(tpf * linSpeed * value));
}
if ("BkwM".equals(name)) {
rotH.move(cam.getDirection().mult(tpf * -linSpeed * value));
}
} else {
// anchor is set, move around it
speed = +rotSpeed * 100 * value;
if ("FwdM".equals(name)) {
System.out.println("FWD " + value);
translate.move(0, 0, tpf * linSpeed * value);
}
if ("BkwM".equals(name)) {
System.out.println("BKWD " + value);
translate.move(0, 0, tpf * -linSpeed * value);
}
}
if (clicked || !dragToRotate) {
if ("UpM".equals(name)) {
rotV.rotate(tpf * speed, 0, 0);
if (dragToRotate) {
dragged = true;
}
}
if ("DownM".equals(name)) {
rotV.rotate(tpf * -speed, 0, 0);
if (dragToRotate) {
dragged = true;
}
}
if (cam.getUp().dot(Vector3f.UNIT_Y) < 0)
speed = - speed;
if ("LeftM".equals(name)) {
rotH.rotate(0, tpf * -speed, 0);
if (dragToRotate) {
dragged = true;
}
}
if ("RightM".equals(name)) {
rotH.rotate(0, tpf * speed, 0);
if (dragToRotate) {
dragged = true;
}
}
} // if rotation allowed
} // onAnalog(…)
} // class FlyAroundAppState
[/java]