[Solved] Chase cam doesnt follow rotation

Hi there! My first week with jmonkeyengine and also my first post on forum! I was wondering if someone could help me as IRC seems pretty quiet - I can’t seem to get the chaseCam to rotate around an object in space when I rotate it and it looks right compared to all the sample tutorials and posts I read - any ideas?



[java]package com.soliniaonline.opencosmos;



import com.jme3.app.SimpleApplication;

import com.jme3.audio.AudioNode;



import com.jme3.input.ChaseCamera;

import com.jme3.input.FlyByCamera;

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.MouseButtonTrigger;

import com.jme3.material.Material;

import com.jme3.math.ColorRGBA;

import com.jme3.math.FastMath;

import com.jme3.math.Vector3f;

import com.jme3.post.FilterPostProcessor;

import com.jme3.post.filters.BloomFilter;

import com.jme3.renderer.Camera;

import com.jme3.scene.Geometry;

import com.jme3.scene.Spatial;

import com.jme3.scene.shape.Box;

import com.jme3.system.AppSettings;

import com.jme3.system.Timer;

import com.jme3.util.SkyFactory;



public class Main extends SimpleApplication {



private AudioNode audio_ambient_space;

protected Spatial player;

Boolean isRunning=true;

private ChaseCamera chaseCam;



@Override

public void simpleInitApp() {



//

// * Scene Backdrop

//



this.setDisplayFps(false);

this.setDisplayStatView(false);

rootNode.attachChild(SkyFactory.createSky(

assetManager, “Textures/Sky/sample.dds”, false));



audio_ambient_space = new AudioNode(assetManager, “Sounds/ambient/space_hollowwind.ogg”, false);

audio_ambient_space.setLooping(true); // activate continuous playing

audio_ambient_space.setPositional(true);

audio_ambient_space.setLocalTranslation(Vector3f.ZERO.clone());

audio_ambient_space.setVolume((float) 0.2);

rootNode.attachChild(audio_ambient_space);

audio_ambient_space.play(); // play continuously!





//

// * Sample player

//



player = assetManager.loadModel(“Models/Ships/base.obj”);

player.setName(“player”);

player.setLocalTranslation(Vector3f.ZERO);

Material mat_default = new Material(

assetManager, “Common/MatDefs/Misc/ShowNormals.j3md”);

player.setMaterial(mat_default);

//ship.scale((float) 0.01);



initKeys();



FilterPostProcessor fpp=new FilterPostProcessor(assetManager);

BloomFilter bloom=new BloomFilter();

bloom.setBloomIntensity(2.2f);

fpp.addFilter(bloom);

viewPort.addProcessor(fpp);



flyCam.setEnabled(false);

mouseInput.setCursorVisible(false);

this.chaseCam = new ChaseCamera(cam, player);

chaseCam.setEnabled(true);

chaseCam.setSmoothMotion(true);

player.addControl(chaseCam);



rootNode.attachChild(player);



}







private void initKeys() {

// TODO Auto-generated method stub

inputManager.addMapping(“Pause”, new KeyTrigger(KeyInput.KEY_P));

inputManager.addMapping(“RotateUp”, new KeyTrigger(KeyInput.KEY_W));

inputManager.addMapping(“RotateDown”, new KeyTrigger(KeyInput.KEY_S));

inputManager.addMapping(“RotateLeft”, new KeyTrigger(KeyInput.KEY_A));

inputManager.addMapping(“RotateRight”, new KeyTrigger(KeyInput.KEY_D));

inputManager.addMapping(“Accelerate”, new KeyTrigger(KeyInput.KEY_SPACE));





// Add the names to the action listener.

inputManager.addListener(analogListener, new String[]{“RotateLeft”});

inputManager.addListener(analogListener, new String[]{“RotateRight”});

inputManager.addListener(analogListener, new String[]{“RotateUp”});

inputManager.addListener(analogListener, new String[]{“RotateDown”});

inputManager.addListener(actionListener, new String[]{“Pause”});

inputManager.addListener(analogListener, new String[]{“Accelerate”});



}



private ActionListener actionListener = new ActionListener() {

public void onAction(String name, boolean keyPressed, float tpf) {

if (name.equals(“Pause”) && !keyPressed) {

isRunning = !isRunning;

}



}

};



private AnalogListener analogListener = new AnalogListener() {

public void onAnalog(String name, float value, float tpf) {

if (isRunning) {

if (name.equals(“RotateLeft”)) {

player.rotate(0.001f, 0, 0);

}

if (name.equals(“RotateRight”)) {

player.rotate(-0.001f, 0, 0);

}

if (name.equals(“RotateUp”)) {

player.rotate(0, 0,0.001f);

}

if (name.equals(“RotateDown”)) {

player.rotate(0,0,-0.001f);

}

if (name.equals(“Accelerate”)) {

// do nothing for now

}

} else {

System.out.println(“Press P to unpause.”);

}

}

};







/**

  • @param args

    */

    public static void main(String[] args) {

    // TODO Auto-generated method stub

    Main app = new Main();



    AppSettings settings = new AppSettings(true);

    settings.setTitle("OpenCosmos");

    settings.setResolution(1024,768);

    settings.setBitsPerPixel(32);

    settings.setFullscreen(false);



    app.setSettings(settings);

    app.setShowSettings(false);

    app.start(); // start the game

    }



    }

    [/java]

Sorry but i don’t understand your issue, could you describe it a bit more?

in line 80 above you have:

[java]

player.addControl(chaseCam);

[/java]

i do not believe chaseCam works as a control, i dont think this line is even needed.

the ChaseCamera is “attached” to the “player” in chaseCam’s constructor when you supply the “spatial” parameter.



also, the chaseCam works by using the (default) mousedrag to rotate around the given spatial separately from the spatials rotation.

if you want the camera to turn always when the spatial turns, you might want to consider using a CameraNode instead of the ChaseCamera.

check this link to help compare and contrast the two ways.



just a few suggestions, i hope they help.

1 Like
Decoy said:
in line 80 above you have:
[java]
player.addControl(chaseCam);
[/java]
i do not believe chaseCam works as a control, i dont think this line is even needed.
the ChaseCamera is "attached" to the "player" in chaseCam's constructor when you supply the "spatial" parameter.

also, the chaseCam works by using the (default) mousedrag to rotate around the given spatial separately from the spatials rotation.
if you want the camera to turn always when the spatial turns, you might want to consider using a CameraNode instead of the ChaseCamera.
check this link to help compare and contrast the two ways.

just a few suggestions, i hope they help.


Thanks! I am just looking at the sample you linked now however the line 'target.attachChild' doesn't seem to exist for my spatial player object (The method attachChild(CameraNode) is undefined for the type Spatial (player.attachChild(this.camnode);) - see below)

any ideas?

[java]package com.soliniaonline.opencosmos;

import com.jme3.app.SimpleApplication;
import com.jme3.audio.AudioNode;

import com.jme3.input.ChaseCamera;
import com.jme3.input.FlyByCamera;
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.MouseButtonTrigger;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Vector3f;
import com.jme3.post.FilterPostProcessor;
import com.jme3.post.filters.BloomFilter;
import com.jme3.renderer.Camera;
import com.jme3.scene.CameraNode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Box;
import com.jme3.system.AppSettings;
import com.jme3.system.Timer;
import com.jme3.util.SkyFactory;

public class Main extends SimpleApplication {

private AudioNode audio_ambient_space;
protected Spatial player;
Boolean isRunning=true;
private CameraNode camnode;

@Override
public void simpleInitApp() {

//
// * Scene Backdrop
//

this.setDisplayFps(false);
this.setDisplayStatView(false);
rootNode.attachChild(SkyFactory.createSky(
assetManager, "Textures/Sky/sample.dds", false));

audio_ambient_space = new AudioNode(assetManager, "Sounds/ambient/space_hollowwind.ogg", false);
audio_ambient_space.setLooping(true); // activate continuous playing
audio_ambient_space.setPositional(true);
audio_ambient_space.setLocalTranslation(Vector3f.ZERO.clone());
audio_ambient_space.setVolume((float) 0.2);
rootNode.attachChild(audio_ambient_space);
audio_ambient_space.play(); // play continuously!


//
// * Sample player
//

player = assetManager.loadModel("Models/Ships/base.obj");
player.setName("player");
player.setLocalTranslation(Vector3f.ZERO);
Material mat_default = new Material(
assetManager, "Common/MatDefs/Misc/ShowNormals.j3md");
player.setMaterial(mat_default);
//ship.scale((float) 0.01);

initKeys();

FilterPostProcessor fpp=new FilterPostProcessor(assetManager);
BloomFilter bloom=new BloomFilter();
bloom.setBloomIntensity(2.2f);
fpp.addFilter(bloom);
viewPort.addProcessor(fpp);

flyCam.setEnabled(false);
mouseInput.setCursorVisible(false);
this.camnode = new CameraNode("Camera Node", cam);
this.camnode.lookAt(player.getLocalTranslation(), Vector3f.UNIT_Y);
player.attachChild(this.camnode);
camnode.setEnabled(true);



rootNode.attachChild(player);

}



private void initKeys() {
// TODO Auto-generated method stub
inputManager.addMapping("Pause", new KeyTrigger(KeyInput.KEY_P));
inputManager.addMapping("RotateUp", new KeyTrigger(KeyInput.KEY_W));
inputManager.addMapping("RotateDown", new KeyTrigger(KeyInput.KEY_S));
inputManager.addMapping("RotateLeft", new KeyTrigger(KeyInput.KEY_A));
inputManager.addMapping("RotateRight", new KeyTrigger(KeyInput.KEY_D));
inputManager.addMapping("Accelerate", new KeyTrigger(KeyInput.KEY_SPACE));


// Add the names to the action listener.
inputManager.addListener(analogListener, new String[]{"RotateLeft"});
inputManager.addListener(analogListener, new String[]{"RotateRight"});
inputManager.addListener(analogListener, new String[]{"RotateUp"});
inputManager.addListener(analogListener, new String[]{"RotateDown"});
inputManager.addListener(actionListener, new String[]{"Pause"});
inputManager.addListener(analogListener, new String[]{"Accelerate"});

}

private ActionListener actionListener = new ActionListener() {
public void onAction(String name, boolean keyPressed, float tpf) {
if (name.equals("Pause") && !keyPressed) {
isRunning = !isRunning;
}

}
};

private AnalogListener analogListener = new AnalogListener() {
public void onAnalog(String name, float value, float tpf) {
if (isRunning) {
if (name.equals("RotateLeft")) {
player.rotate(0.001f, 0, 0);
}
if (name.equals("RotateRight")) {
player.rotate(-0.001f, 0, 0);
}
if (name.equals("RotateUp")) {
player.rotate(0, 0,0.001f);
}
if (name.equals("RotateDown")) {
player.rotate(0,0,-0.001f);
}
if (name.equals("Accelerate")) {
// do nothing for now
}
} else {
System.out.println("Press P to unpause.");
}
}
};



/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Main app = new Main();

AppSettings settings = new AppSettings(true);
settings.setTitle("OpenCosmos");
settings.setResolution(1024,768);
settings.setBitsPerPixel(32);
settings.setFullscreen(false);

app.setSettings(settings);
app.setShowSettings(false);
app.start(); // start the game
}

}
[/java]
Decoy said:
in line 80 above you have:
[java]
player.addControl(chaseCam);
[/java]
i do not believe chaseCam works as a control, i dont think this line is even needed.
the ChaseCamera is "attached" to the "player" in chaseCam's constructor when you supply the "spatial" parameter.

Actually it does.
ChaseCam is a control, and this
[java]
player.addControl(chaseCam);
[/java]
does exactly the same as setting the spatial in the constructor
1 Like

Thanks again - i looked through the examples a bit more you sent me and found a teapot one that worked quite well - it seemed to allow it to be attached by using a Node which a geometry was placed inside!



So i guess this is now solved! Kudos!



[java]package com.soliniaonline.opencosmos;



import com.jme3.app.SimpleApplication;

import com.jme3.audio.AudioNode;



import com.jme3.input.controls.AnalogListener;

import com.jme3.input.controls.KeyTrigger;

import com.jme3.material.Material;

import com.jme3.math.Vector3f;

import com.jme3.scene.CameraNode;

import com.jme3.scene.Geometry;

import com.jme3.scene.Node;

import com.jme3.scene.control.CameraControl.ControlDirection;

import com.jme3.system.AppSettings;

import com.jme3.util.SkyFactory;



public class Main extends SimpleApplication {



private Geometry playerGeom;

private Node playerNode;

CameraNode camNode;

boolean rotate = false;

Vector3f direction = new Vector3f();

private AudioNode audio_ambient_space;





public void simpleInitApp() {



rootNode.attachChild(SkyFactory.createSky(

assetManager, “Textures/Sky/sample.dds”, false));



audio_ambient_space = new AudioNode(assetManager, “Sounds/ambient/space_hollowwind.ogg”, false);

audio_ambient_space.setLooping(true); // activate continuous playing

audio_ambient_space.setPositional(true);

audio_ambient_space.setLocalTranslation(Vector3f.ZERO.clone());

audio_ambient_space.setVolume((float) 0.2);

rootNode.attachChild(audio_ambient_space);

audio_ambient_space.play(); // play continuously!



// load the player ship model

playerGeom = (Geometry) assetManager.loadModel(“Models/Ships/base.obj”);

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

playerGeom.setMaterial(mat);

//create a node to attach the geometry and the camera node

playerNode = new Node(“playerNode”);

playerNode.attachChild(playerGeom);

rootNode.attachChild(playerNode);



//creating the camera Node

camNode = new CameraNode(“CamNode”, cam);

//Setting the direction to Spatial to camera, this means the camera will copy the movements of the Node

camNode.setControlDir(ControlDirection.SpatialToCamera);

//attaching the camNode to the playerNode

playerNode.attachChild(camNode);

//setting the local translation of the cam node to move it away from the playerNode a bit

camNode.setLocalTranslation(new Vector3f(-10, 0, 0));

//setting the camNode to look at the playerNode

camNode.lookAt(playerNode.getLocalTranslation(), Vector3f.UNIT_Y);



//disable the default 1st-person flyCam (don’t forget this!!)

flyCam.setEnabled(false);



registerInput();

}



public void registerInput() {

inputManager.addMapping(“moveForward”, new KeyTrigger(keyInput.KEY_SPACE));

inputManager.addMapping(“moveUp”, new KeyTrigger(keyInput.KEY_UP), new KeyTrigger(keyInput.KEY_W));

inputManager.addMapping(“moveDown”, 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.addListener(analogListener, new String[]{“moveUp”});

inputManager.addListener(analogListener, new String[]{“moveDown”});

inputManager.addListener(analogListener, new String[]{“moveForward”});

inputManager.addListener(analogListener, new String[]{“moveBackward”});

inputManager.addListener(analogListener, new String[]{“moveRight”});

inputManager.addListener(analogListener, new String[]{“moveLeft”});





}

private AnalogListener analogListener = new AnalogListener() {

public void onAnalog(String name, float value, float tpf) {

//computing the normalized direction of the cam to move the teaNode

direction.set(cam.getDirection()).normalizeLocal();

if (name.equals(“moveForward”)) {

direction.multLocal(5 * tpf);

playerNode.move(direction);

}

if (name.equals(“moveUp”)) {

playerNode.rotate(0, 0, -1 * tpf);

}

if (name.equals(“moveDown”)) {

playerNode.rotate(0, 0, 1 * tpf);

}

if (name.equals(“moveRight”)) {

playerNode.rotate(-1 * tpf, 0, 0);

}

if (name.equals(“moveLeft”)) {

playerNode.rotate(1 * tpf, 0, 0);

}

}

};



/**

  • @param args

    */

    public static void main(String[] args) {

    // TODO Auto-generated method stub

    Main app = new Main();





    AppSettings settings = new AppSettings(true);

    settings.setTitle("OpenCosmos");

    settings.setResolution(1024,768);

    settings.setFrameRate(100);

    settings.setBitsPerPixel(32);

    settings.setFullscreen(false);



    app.setSettings(settings);

    app.setShowSettings(false);

    app.start(); // start the game

    }



    }

    [/java]