Now it tilts and it’s almost perfect. I changed to a RigidBodyControl and then the moving and tilting works.
[java] @Override
public void simpleUpdate(float tpf) {
int speed = 50 * 80000;
Vector3f camDir = cam.getDirection().clone().multLocal(speed * tpf);
Vector3f camUp = cam.getUp().clone().mult(speed * tpf);
Quaternion roll = new Quaternion();
camDir.y = 0;
ufoDirection.set(0, 0, 0);
ufoControl.setLinearVelocity(Vector3f.ZERO);
if (left) {
roll.fromAngleAxis(-FastMath.QUARTER_PI/2, cam.getDirection());
ufoDirection.set(cam.getLeft().multLocal(speed * tpf));
}
if (right) {
roll.fromAngleAxis(FastMath.QUARTER_PI/2, cam.getDirection());
//ufoControl.setPhysicsRotation(roll);
ufoDirection.set(cam.getLeft()).multLocal(-speed * tpf);
}
if (up) {
roll.fromAngleAxis(0, cam.getDirection());
//ufoControl.setPhysicsRotation(roll);
ufoDirection.addLocal(camUp);
}
if (down) {
roll.fromAngleAxis(0, cam.getDirection());
//ufoControl.setPhysicsRotation(roll);
ufoDirection.addLocal(cam.getUp().multLocal(-speed * tpf));
}
if (forward) {
roll.fromAngleAxis(0, cam.getDirection());
//ufoControl.setPhysicsRotation(roll);
ufoDirection.set(camDir);
}
if (backward) {
roll.fromAngleAxis(0, cam.getDirection());
//ufoControl.setPhysicsRotation(roll);
ufoDirection.set(camDir.multLocal(-1f));
}
ufoControl.setPhysicsRotation(roll);
ufoControl.setLinearVelocity(ufoDirection);
}
[/java]
I’m manipulating the ufoControl now instead of the node in the update code. The complete rewritten app / game is
[java]public class UFOSpaceWorld extends SimpleApplication implements AnalogListener,
ActionListener {
private PlanetAppState planetAppState;
private Geometry mark;
private Node ufoNode;
private Node spaceStationNode;
private Node jumpgateNode;
private Node jumpgateNode2;
private RigidBodyControl ufoControl;
private BetterCharacterControl spaceStationControl;
CameraNode camNode;
ChaseCamera chaseCam;
boolean rotate = false;
static UFOSpaceWorld app;
Vector3f ufoDirection = new Vector3f();
private BulletAppState bulletAppState;
private boolean left = false, right = false, up = false, down = false,
forward = false, backward = false, attack = false;
private void setupChaseCamera() {
flyCam.setEnabled(false);
chaseCam = new ChaseCamera(cam, ufoNode, inputManager);
chaseCam.setDefaultDistance(2237);
}
public static void main(String[] args) {
AppSettings settings = new AppSettings(true);
settings.setResolution(1280, 1024);
app = new UFOSpaceWorld();
app.setSettings(settings);
app.start();
}
@Override
public void simpleInitApp() {
this.setDisplayStatView(false);
setDisplayFps(false);
// Only show severe errors in log
java.util.logging.Logger.getLogger("com.jme3").setLevel(
java.util.logging.Level.SEVERE);
bulletAppState = new BulletAppState();
bulletAppState.setThreadingType(BulletAppState.ThreadingType.PARALLEL);
stateManager.attach(bulletAppState);
bulletAppState.setDebugEnabled(false);
DirectionalLight sun = new DirectionalLight();
sun.setDirection(new Vector3f(-.1f, 0f, -1f));
sun.setColor(new ColorRGBA(0.75f, 0.75f, 0.75f, 1.0f));
rootNode.addLight(sun);
// Add sky
Node sceneNode = new Node("Scene");
sceneNode.attachChild(Utility.createSkyBox(this.getAssetManager(),
"Textures/blue-glow-1024.dds"));
rootNode.attachChild(sceneNode);
// Create collision test mark
Sphere sphere = new Sphere(30, 30, 5f);
mark = new Geometry("mark", sphere);
Material mark_mat = new Material(assetManager,
"Common/MatDefs/Misc/Unshaded.j3md");
mark_mat.setColor("Color", ColorRGBA.Red);
mark.setMaterial(mark_mat);
// Add planet app state
planetAppState = new PlanetAppState(rootNode, sun);
stateManager.attach(planetAppState);
// Add planet
FractalDataSource planetDataSource = new FractalDataSource(4);
planetDataSource.setHeightScale(900f);
Planet planet = Utility.createEarthLikePlanet(getAssetManager(),
293710.0f, null, planetDataSource);
planetAppState.addPlanet(planet);
rootNode.attachChild(planet);
// Add moon
FractalDataSource moonDataSource = new FractalDataSource(5);
moonDataSource.setHeightScale(300f);
Planet moon = Utility.createMoonLikePlanet(getAssetManager(), 50000,
moonDataSource);
planetAppState.addPlanet(moon);
rootNode.attachChild(moon);
moon.setLocalTranslation(new Vector3f(10f, 10f, 705000f));
// add saucer
ufoNode = (Node) assetManager.loadModel("usaucer_v01.j3o");
ufoNode.setLocalScale(100f);
ufoNode.setLocalTranslation((new Vector3f(1000f, -1000f, 328000f)));
jumpgateNode = (Node) assetManager.loadModel("JumpGate.j3o");
jumpgateNode.setLocalScale(10000f);
jumpgateNode.setLocalTranslation((new Vector3f(10f, 10f, 908000f)));
spaceStationNode = (Node) assetManager.loadModel("SpaceStation.j3o");
spaceStationNode.setLocalScale(2000f);
spaceStationNode.setLocalTranslation((new Vector3f(10000f, -10f,
625000f)));
jumpgateNode2 = (Node) assetManager.loadModel("JumpGate.j3o");
jumpgateNode2.setLocalScale(10000f);
jumpgateNode2.setLocalTranslation((new Vector3f(10f, 10f, 998300f)));
rootNode.attachChild(jumpgateNode);
rootNode.attachChild(jumpgateNode2);
//rootNode.attachChild(spaceStationNode);
ufoControl = new RigidBodyControl( 50f);
//new BetterCharacterControl100f, 80f,
// radius (meters), height (meters), gravity (mass)
System.out.println("space station local scale: "+spaceStationNode.getLocalScale());
System.out.println("ufo local scale: "+ufoNode.getLocalScale());
spaceStationControl = new BetterCharacterControl(4000f, 8000f, 900f);
//ufoControl.setPhysicsDamping(0);
ufoNode.addControl(ufoControl);
spaceStationNode.addControl(spaceStationControl);
//ufoControl.setGravity(new Vector3f(0,0,0));
rootNode.attachChild(ufoNode);
bulletAppState.getPhysicsSpace().add(ufoControl);
getPhysicsSpace().add(ufoControl);
rootNode.attachChild(spaceStationNode);
bulletAppState.getPhysicsSpace().add(spaceStationControl);
getPhysicsSpace().add(spaceStationControl);
bulletAppState.getPhysicsSpace().setGravity(new Vector3f(0, 0, 0));
setupChaseCamera();
registerInput();
}
private PhysicsSpace getPhysicsSpace() {
return bulletAppState.getPhysicsSpace();
}
public void registerInput() {
inputManager.addMapping("moveForward", new KeyTrigger(keyInput.KEY_UP),
new KeyTrigger(keyInput.KEY_W));
inputManager.addMapping("moveBackward", new KeyTrigger(
keyInput.KEY_DOWN), new KeyTrigger(keyInput.KEY_S));
inputManager.addMapping("moveRight",
new KeyTrigger(keyInput.KEY_RIGHT), new KeyTrigger(
keyInput.KEY_D));
inputManager.addMapping("moveLeft", new KeyTrigger(keyInput.KEY_LEFT),
new KeyTrigger(keyInput.KEY_A));
inputManager.addMapping("moveUp", new KeyTrigger(keyInput.KEY_E));
inputManager.addMapping("moveDown", new KeyTrigger(keyInput.KEY_Q));
inputManager.addMapping("toggleRotate", new MouseButtonTrigger(
MouseInput.BUTTON_LEFT));
inputManager.addMapping("rotateRight", new MouseAxisTrigger(
MouseInput.AXIS_X, true));
inputManager.addMapping("rotateLeft", new MouseAxisTrigger(
MouseInput.AXIS_X, false));
inputManager.addMapping("rotateUp", new MouseAxisTrigger(
MouseInput.AXIS_Y, true));
inputManager.addMapping("rotateDown", new MouseAxisTrigger(
MouseInput.AXIS_Y, false));
inputManager.addListener(this, "moveForward", "moveBackward",
"moveRight", "moveLeft", "moveUp", "moveDown");
inputManager.addListener(this, "rotateRight", "rotateLeft", "rotateUp",
"rotateDown", "toggleRotate");
// Toggle mouse cursor
inputManager.addMapping("TOGGLE_CURSOR", new MouseButtonTrigger(
MouseInput.BUTTON_LEFT), new KeyTrigger(KeyInput.KEY_SPACE));
inputManager.addListener(actionListener, "TOGGLE_CURSOR");
// Toggle wireframe
inputManager.addMapping("TOGGLE_WIREFRAME", new KeyTrigger(
KeyInput.KEY_T));
inputManager.addListener(actionListener, "TOGGLE_WIREFRAME");
// Collision test
inputManager.addMapping("COLLISION_TEST", new MouseButtonTrigger(
MouseInput.BUTTON_RIGHT));
inputManager.addListener(actionListener, "COLLISION_TEST");
}
public void toggleToFullscreen() {
GraphicsDevice device = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
DisplayMode[] modes = device.getDisplayModes();
int i=0; // note: there are usually several, let's pick the first
settings.setResolution(modes[i].getWidth(),modes[i].getHeight());
settings.setFrequency(modes[i].getRefreshRate());
settings.setBitsPerPixel(modes[i].getBitDepth());
settings.setFullscreen(device.isFullScreenSupported());
app.setSettings(settings);
app.restart(); // restart the context to apply changes
}
@Override
public void simpleUpdate(float tpf) {
int speed = 50 * 80000;
Vector3f camDir = cam.getDirection().clone().multLocal(speed * tpf);
Vector3f camUp = cam.getUp().clone().mult(speed * tpf);
Quaternion roll = new Quaternion();
camDir.y = 0;
ufoDirection.set(0, 0, 0);
ufoControl.setLinearVelocity(Vector3f.ZERO);
if (left) {
roll.fromAngleAxis(-FastMath.QUARTER_PI/2, cam.getDirection());
ufoDirection.set(cam.getLeft().multLocal(speed * tpf));
}
if (right) {
roll.fromAngleAxis(FastMath.QUARTER_PI/2, cam.getDirection());
//ufoControl.setPhysicsRotation(roll);
ufoDirection.set(cam.getLeft()).multLocal(-speed * tpf);
}
if (up) {
roll.fromAngleAxis(0, cam.getDirection());
//ufoControl.setPhysicsRotation(roll);
ufoDirection.addLocal(camUp);
}
if (down) {
roll.fromAngleAxis(0, cam.getDirection());
//ufoControl.setPhysicsRotation(roll);
ufoDirection.addLocal(cam.getUp().multLocal(-speed * tpf));
}
if (forward) {
roll.fromAngleAxis(0, cam.getDirection());
//ufoControl.setPhysicsRotation(roll);
ufoDirection.set(camDir);
}
if (backward) {
roll.fromAngleAxis(0, cam.getDirection());
//ufoControl.setPhysicsRotation(roll);
ufoDirection.set(camDir.multLocal(-1f));
}
ufoControl.setPhysicsRotation(roll);
ufoControl.setLinearVelocity(ufoDirection);
}
public void onAnalog(String name, float value, float tpf) {
if (name.equals("rotateRight") && rotate) {
System.out.println("rotateRight");
ufoNode.rotate(0, 1 * tpf, 0);
}
if (name.equals("rotateLeft") && rotate) {
System.out.println("rotateLeft");
ufoNode.rotate(0, -1 * tpf, 0);
}
if (name.equals("rotateUp") && rotate) {
System.out.println("rotateUp");
ufoNode.rotate(0, 0, -1 * tpf);
}
if (name.equals("rotateDown") && rotate) {
System.out.println("rotateDown");
ufoNode.rotate(0, 0, 1 * tpf);
}
}
public void onAction(String name, boolean keyPressed, float tpf) {
if (name.equals("moveLeft")) {
if (keyPressed) {
left = true;
} else {
left = false;
}
} else if (name.equals("moveRight")) {
if (keyPressed) {
right = true;
} else {
right = false;
}
} else if (name.equals("moveUp")) {
if (keyPressed) {
up = true;
} else {
up = false;
}
} else if (name.equals("moveDown")) {
if (keyPressed) {
down = true;
} else {
down = false;
}
} else if (name.equals("moveForward")) {
if (keyPressed) {
forward = true;
} else {
forward = false;
}
} else if (name.equals("moveBackward")) {
if (keyPressed) {
backward = true;
} else {
backward = false;
}
}
// toggling rotation on or off
if (name.equals("toggleRotate") && keyPressed) {
rotate = true;
inputManager.setCursorVisible(false);
}
if (name.equals("toggleRotate") && !keyPressed) {
rotate = false;
inputManager.setCursorVisible(true);
}
if (name.equals("TOGGLE_CURSOR") && !keyPressed) {
if (inputManager.isCursorVisible()) {
inputManager.setCursorVisible(false);
} else {
inputManager.setCursorVisible(true);
}
}
if (name.equals("TOGGLE_WIREFRAME") && !keyPressed) {
for (Planet planet : planetAppState.getPlanets()) {
planet.toogleWireframe();
}
}
if (name.equals("COLLISION_TEST") && !keyPressed) {
CollisionResults results = new CollisionResults();
Ray ray = new Ray(cam.getLocation(), cam.getDirection());
// Test collision with closest planet's terrain only
planetAppState.getNearestPlanet().getTerrainNode()
.collideWith(ray, results);
System.out.println("----- Collisions? " + results.size() + "-----");
for (int i = 0; i < results.size(); i++) {
// For each hit, we know distance, impact point, name of
// geometry.
float dist = results.getCollision(i).getDistance();
Vector3f pt = results.getCollision(i).getContactPoint();
String hit = results.getCollision(i).getGeometry().getName();
System.out.println("* Collision #" + i);
System.out.println(" You shot " + hit + " at " + pt + ", "
+ dist + " wu away.");
}
if (results.size() > 0) {
// The closest collision point is what was truly hit:
CollisionResult closest = results.getClosestCollision();
// Let's interact - we mark the hit with a red dot.
mark.setLocalTranslation(closest.getContactPoint());
rootNode.attachChild(mark);
} else {
// No hits? Then remove the red mark.
rootNode.detachChild(mark);
}
}
}
private ActionListener actionListener = new ActionListener() {
public void onAction(String name, boolean pressed, float tpf) {
if (name.equals("TOGGLE_CURSOR") && !pressed) {
if (inputManager.isCursorVisible()) {
inputManager.setCursorVisible(false);
} else {
inputManager.setCursorVisible(true);
}
}
if (name.equals("TOGGLE_WIREFRAME") && !pressed) {
for (Planet planet : planetAppState.getPlanets()) {
planet.toogleWireframe();
}
}
if (name.equals("COLLISION_TEST") && !pressed) {
CollisionResults results = new CollisionResults();
Ray ray = new Ray(cam.getLocation(), cam.getDirection());
// Test collision with closest planet's terrain only
planetAppState.getNearestPlanet().getTerrainNode()
.collideWith(ray, results);
System.out.println("----- Collisions? " + results.size()
+ "-----");
for (int i = 0; i < results.size(); i++) {
// For each hit, we know distance, impact point, name of
// geometry.
float dist = results.getCollision(i).getDistance();
Vector3f pt = results.getCollision(i).getContactPoint();
String hit = results.getCollision(i).getGeometry()
.getName();
System.out.println("* Collision #" + i);
System.out.println(" You shot " + hit + " at " + pt + ", "
+ dist + " wu away.");
}
if (results.size() > 0) {
// The closest collision point is what was truly hit:
CollisionResult closest = results.getClosestCollision();
// Let's interact - we mark the hit with a red dot.
mark.setLocalTranslation(closest.getContactPoint());
rootNode.attachChild(mark);
} else {
// No hits? Then remove the red mark.
rootNode.detachChild(mark);
}
}
}
};
}
[/java]
And having rewritten it to use a RigidBodyControl now the gameplay is somewhat different but it is rendering everything except the tilting that I want to achieve.THe UFO now does tilt.[video]http://youtu.be/wtP14tj-I4k[/video]