Problems with Chasecamera

Hi,



I'm trying to create a thirdpersonhandler with a chasecamera in my project. For that I use the example from jME "TestThirdPersonController.java". In this example is a box the character, but when I try to use my own model that I've created in Blender and imported it into jME as an xml-file, I get a NullPointerException int this line:



targetOffset.y = ((BoundingBox) m_character.getWorldBound()).yExtent * 1.5f;



and this is the code for my character:



private void setupCharacter(){

try {

  //Initialise binary converter

XMLtoBinary converter = new XMLtoBinary();

 

//Initialise binary reader

JmeBinaryReader jbr = new JmeBinaryReader();

 

//Initialise binary writer

JmeBinaryWriter jbw = new JmeBinaryWriter();



  //convert the input file to a jme-binary "Dummy"

  ByteArrayOutputStream Dummy = new ByteArrayOutputStream();

  URL BodyModel = ModelLoader.class.getClassLoader().getResource("body2.xml");

  converter.sendXMLtoBinary(new BufferedInputStream(BodyModel.openStream()), Dummy);

       

  //get the "Dummy"

  Node StickMan = jbr.loadBinaryFormat(new ByteArrayInputStream(Dummy.toByteArray()));

       

  //write the "Dummy"

  ByteArrayOutputStream BO6 = new ByteArrayOutputStream();

  jbw.writeScene(StickMan,BO6);

 

  //Send the new jME binary to a jME SceneGraph and attach it.

  StickMan = jbr.loadBinaryFormat(new ByteArrayInputStream(BO6.toByteArray()));

  StickMan.setModelBound(new BoundingBox());

  StickMan.updateModelBound();

  m_character = new Node("char node");

  rootNode.attachChild(m_character);

  m_character.attachChild(StickMan);

  m_character.updateWorldBound();

  // attach our TV to the scene grap

  //rootNode.attachChild(StickMan);

}catch (IOException e){

  System.out.println("Couldn't load the input file:" + e);

  e.printStackTrace();}

  catch (java.lang.NullPointerException npe ) {

    npe.printStackTrace();

  }

}



Maybe somebody of you can explain what I'm doing wrong.

hi,



when I change the line: targetOffset.y = ((BoundingBox) m_character.getWorldBound()).yExtent * 1.5f;

to:        targetOffset.y = 1.5f; so the program runs



Does someone know why I can't use the first line?

Now I have created a Chasecamera and a Thirdpersonhandler, but now … when I move my character the Chasecamera is not behind him but rather in front of him. Can someone help me to solve this prob?



this is my ChaseCamera :



private void setupChaseCamera() {

    Vector3f targetOffset = new Vector3f();

    //targetOffset.y = ((BoundingBox) m_character.getWorldBound()).yExtent * 1.5f;

    targetOffset.y = 0.5f;

    chaser = new ChaseCamera(cam, m_character);

    chaser.setTargetOffset(targetOffset);

    chaser.setMinDistance(5);

    chaser.setMaxDistance(5);

}

The null came from your model not having bounding volume information.  You can call:


m_character.setModelBound(new BoundingBox());
m_character.updateModelBound();
m_character.updateWorldBound();



Not sure about the camera in front thing.  Do you mean it actually moves to be in the position your player is moving to, or you mean the model is turned around when it moves?

Thanks for your reply. I changed my Character-Method to this:



private void setupCharacter(){

try {

  XMLtoBinary converter = new XMLtoBinary();

  JmeBinaryReader jbr = new JmeBinaryReader();

  JmeBinaryWriter jbw = new JmeBinaryWriter();

  ByteArrayOutputStream Dummy = new ByteArrayOutputStream();

  URL BodyModel = ModelLoader.class.getClassLoader().getResource("body2.xml");

  converter.sendXMLtoBinary(new BufferedInputStream(BodyModel.openStream()), Dummy);

  StickMan = jbr.loadBinaryFormat(new ByteArrayInputStream(Dummy.toByteArray()));

  ByteArrayOutputStream BO6 = new ByteArrayOutputStream();

  jbw.writeScene(StickMan,BO6);

  StickMan = jbr.loadBinaryFormat(new ByteArrayInputStream(BO6.toByteArray()));

  m_character = new Node ("char node");

  m_character.setModelBound(new BoundingBox());

  m_character.updateModelBound();

  m_character.updateWorldBound();

  m_character.attachChild(StickMan);

  rootNode.attachChild(m_character);

 

}catch (IOException e){

  System.out.println("Couldn't load the input file:" + e);

  e.printStackTrace();}

catch (java.lang.NullPointerException npe ) {

    npe.printStackTrace();

}

}



but the error is the same.



And the problem with the ChaseCamera in front of the moving object looks like that: when I press any key to move it, the camera turns around and the object stays behind it. It's like a tourist who walks around with his digicam in front of him.  :?

Change this:


                 m_character.setModelBound(new BoundingBox());
                 m_character.updateModelBound();
                 m_character.updateWorldBound();
                 m_character.attachChild(StickMan);



To:

                 m_character.attachChild(StickMan);
                 m_character.setModelBound(new BoundingBox());
                 m_character.updateModelBound();
                 m_character.updateWorldBound();



So the camera is behind the character, but it's looking backwards?

I've changed the code but the error with the targetOffset is still the same  :frowning:



java.lang.NullPointerException

at LaborXMLTest.setupChaseCamera(LaborXMLTest.java:289)

at LaborXMLTest.simpleInitGame(LaborXMLTest.java:60)

at com.jme.app.BaseSimpleGame.initGame(BaseSimpleGame.java:497)

at com.jme.app.BaseGame.start(BaseGame.java:56)

at LaborXMLTest.main(LaborXMLTest.java:47)



And the ChaseCamera…it's very strange… when I press the w-key it turns 180 degrees and is in front of my StickMan.



here is my complete source code:





import java.io.BufferedInputStream;

import java.io.ByteArrayInputStream;

import java.io.ByteArrayOutputStream;

import java.io.IOException;

import java.net.URL;

import java.util.HashMap;

import com.jme.app.SimpleGame;

import com.jme.scene.Node;

import com.jme.scene.state.TextureState;

import com.jme.image.Texture;

import com.jme.input.ChaseCamera;

import com.jme.input.ThirdPersonHandler;

import com.jme.math.FastMath;

import com.jme.math.Vector3f;

import com.jme.util.LoggingSystem;

import com.jme.util.TextureManager;

import com.jmex.model.XMLparser.JmeBinaryReader;

import com.jmex.model.XMLparser.JmeBinaryWriter;

import com.jmex.model.XMLparser.XMLtoBinary;

import com.jmex.model.util.ModelLoader;

import com.jme.scene.state.LightState;

import com.jme.light.PointLight;

import com.jme.renderer.ColorRGBA;

import com.jme.bounding.BoundingBox;

import com.jme.input.InputSystem;

import com.jme.input.joystick.JoystickInput;





//


public class LaborXMLTest extends SimpleGame{
protected LightState lightState;
private Node StickMan;
private Node m_character;
private Node lab;
private ChaseCamera chaser;

    public static void main(String[] args) {
    try {
    JoystickInput.setProvider(InputSystem.INPUT_SYSTEM_LWJGL);
    } catch (Exception e) {
    e.printStackTrace();
    }
    LoggingSystem.getLogger().setLevel(java.util.logging.Level.OFF);
LaborXMLTest app = new LaborXMLTest();
    app.setDialogBehaviour(ALWAYS_SHOW_PROPS_DIALOG);
    app.start();
}
//
 


protected void simpleInitGame() {
display.setTitle("Virtual Lab");
setupCharacter();
setupLabModel();
LightsAndCam();
setupMediaPlayer();
setupTV();
setupWindow();
        setupChaseCamera();
        setupInput();

}

    protected void simpleUpdate() {
        chaser.update(tpf);
     
        float camMinHeight = cam.getLocation().y ;
        if (!Float.isInfinite(camMinHeight) && !Float.isNaN(camMinHeight) && cam.getLocation().y <= camMinHeight) {
            cam.getLocation().y = camMinHeight;
            cam.update();
        }
    }
//
 
private void LightsAndCam(){
  // Set up a basic, default light
  PointLight light = new PointLight();
  light.setDiffuse( new ColorRGBA( 0.75f, 0.75f, 0.75f, 0.75f ) );
  light.setAmbient( new ColorRGBA( 0.5f, 0.5f, 0.5f, 1.0f ) );
  light.setLocation( new Vector3f( 4, 4, 4 ) );
  light.setEnabled( true );
  //Attach the light to a lightState and the lightState to rootNode
  lightState = display.getRenderer().createLightState();
  lightState.setEnabled( true );
  lightState.attach( light );
  rootNode.setRenderState( lightState );

     
  cam.setLocation(new Vector3f(40,30,40));
  cam.lookAt(new Vector3f(20,20,20), new Vector3f(10,10,10));

  cam.update();
}
//
 
private void setupLabModel(){
try {
  //Initialise binary converter
XMLtoBinary converter = new XMLtoBinary();
 
//Initialise binary reader
JmeBinaryReader jbr = new JmeBinaryReader();
 
//Initialise binary writer
JmeBinaryWriter jbw = new JmeBinaryWriter();
  // convert the input file to a jme-binary "LabNoExtra"
  ByteArrayOutputStream LabNoExtra = new ByteArrayOutputStream();
  URL LabModel = ModelLoader.class.getClassLoader().getResource("labnoextra2.xml");
  converter.sendXMLtoBinary(new BufferedInputStream(LabModel.openStream()), LabNoExtra);
 
  //get the "LabNoExtra"
  lab = new Node ("Lab Node");
  lab = jbr.loadBinaryFormat(new ByteArrayInputStream(LabNoExtra.toByteArray()));
   
  // write the "LabNoExtra"
  ByteArrayOutputStream BO2 = new ByteArrayOutputStream();
  jbw.writeScene(lab,BO2);
       
  // Send the new jME binary to a jME SceneGraph and attach it.
  lab = jbr.loadBinaryFormat(new ByteArrayInputStream(BO2.toByteArray()));
   
  // attach our LabNoExtra to the scene grap
  rootNode.attachChild(lab);
}catch (IOException e){
  System.out.println("Couldn't load the input file:" + e);
  e.printStackTrace();}
  catch (java.lang.NullPointerException npe ) {
    npe.printStackTrace();
  }

}
//
 
private void setupMediaPlayer(){
try {
  //Initialise binary converter
XMLtoBinary converter = new XMLtoBinary();
 
//Initialise binary reader
JmeBinaryReader jbr = new JmeBinaryReader();
 
//Initialise binary writer
JmeBinaryWriter jbw = new JmeBinaryWriter();
  //convert the input file to a jme-binary "MediaPlayer"
  ByteArrayOutputStream MediaPlayer = new ByteArrayOutputStream();
  URL MediaPlayerModel = ModelLoader.class.getClassLoader().getResource("dvd.xml");
  converter.sendXMLtoBinary(new BufferedInputStream(MediaPlayerModel.openStream()), MediaPlayer);
       
  //get the "MediaPlayer"
  Node media = jbr.loadBinaryFormat(new ByteArrayInputStream(MediaPlayer.toByteArray()));
       
  //write the "MediaPlayer"
  ByteArrayOutputStream BO3 = new ByteArrayOutputStream();
  jbw.writeScene(media,BO3);
 
  //Send the new jME binary to a jME SceneGraph and attach it.
  media = jbr.loadBinaryFormat(new ByteArrayInputStream(BO3.toByteArray()));
   
  // attach our MediaPlayer to the scene grap
  rootNode.attachChild(media);
}catch (IOException e){
  System.out.println("Couldn't load the input file:" + e);
  e.printStackTrace();}
  catch (java.lang.NullPointerException npe ) {
    npe.printStackTrace();
  }
}
//
 
private void setupTV(){
try {
  //Initialise binary converter
XMLtoBinary converter = new XMLtoBinary();
 
//Initialise binary reader
JmeBinaryReader jbr = new JmeBinaryReader();
 
//Initialise binary writer
JmeBinaryWriter jbw = new JmeBinaryWriter();
  //convert the input file to a jme-binary "TV"
  ByteArrayOutputStream TV = new ByteArrayOutputStream();
  URL TVModel = ModelLoader.class.getClassLoader().getResource("tv.xml");
  converter.sendXMLtoBinary(new BufferedInputStream(TVModel.openStream()), TV);
       
  //get the "TV"
  Node tvscreen = jbr.loadBinaryFormat(new ByteArrayInputStream(TV.toByteArray()));
       
  //write the "TV"
  ByteArrayOutputStream BO4 = new ByteArrayOutputStream();
  jbw.writeScene(tvscreen,BO4);
 
  //Send the new jME binary to a jME SceneGraph and attach it.
  tvscreen = jbr.loadBinaryFormat(new ByteArrayInputStream(BO4.toByteArray()));
   
  // attach our TV to the scene grap
  rootNode.attachChild(tvscreen);
}catch (IOException e){
  System.out.println("Couldn't load the input file:" + e);
  e.printStackTrace();}
  catch (java.lang.NullPointerException npe ) {
    npe.printStackTrace();
  }
}
//
 
private void setupWindow(){
try {
  //Initialise binary converter
XMLtoBinary converter = new XMLtoBinary();
 
//Initialise binary reader
JmeBinaryReader jbr = new JmeBinaryReader();
 
//Initialise binary writer
JmeBinaryWriter jbw = new JmeBinaryWriter();
  //convert the input file to a jme-binary "Window"
  ByteArrayOutputStream Window = new ByteArrayOutputStream();
  URL WindowModel = ModelLoader.class.getClassLoader().getResource("window2.xml");
  converter.sendXMLtoBinary(new BufferedInputStream(WindowModel.openStream()), Window);
       
  //get the "Window"
  Node labwindow = jbr.loadBinaryFormat(new ByteArrayInputStream(Window.toByteArray()));
         
  //write the "Window"
  ByteArrayOutputStream BO5 = new ByteArrayOutputStream();
  jbw.writeScene(labwindow,BO5);
 
  //Send the new jME binary to a jME SceneGraph and attach it.
  labwindow = jbr.loadBinaryFormat(new ByteArrayInputStream(BO5.toByteArray()));
   
  // attach our Window to the scene grap
  //rootNode.attachChild(labwindow);
 
  labwindow.setModelBound(new BoundingBox());
  labwindow.updateModelBound();
 
  TextureState ts = display.getRenderer().createTextureState();
      ts.setEnabled(true);
      ts.setTexture(
          TextureManager.loadTexture(
          LaborXML.class.getClassLoader().getResource(
          "landscape.jpg"),
          Texture.MM_LINEAR_LINEAR,
          Texture.FM_LINEAR));

    // rootNode.setRenderState(ts);
    rootNode.attachChild(labwindow);
}catch (IOException e){
  System.out.println("Couldn't load the input file:" + e);
  e.printStackTrace();}
  catch (java.lang.NullPointerException npe ) {
    npe.printStackTrace();
  }
}
//
 
private void setupCharacter(){
try {
  XMLtoBinary converter = new XMLtoBinary();
  JmeBinaryReader jbr = new JmeBinaryReader();
  JmeBinaryWriter jbw = new JmeBinaryWriter();
  ByteArrayOutputStream Dummy = new ByteArrayOutputStream();
  URL BodyModel = ModelLoader.class.getClassLoader().getResource("body2.xml");
  converter.sendXMLtoBinary(new BufferedInputStream(BodyModel.openStream()), Dummy);
  StickMan = jbr.loadBinaryFormat(new ByteArrayInputStream(Dummy.toByteArray()));
  ByteArrayOutputStream BO6 = new ByteArrayOutputStream();
  jbw.writeScene(StickMan,BO6);
  StickMan = jbr.loadBinaryFormat(new ByteArrayInputStream(BO6.toByteArray()));
  //StickMan.setModelBound(new BoundingBox());
  //StickMan.updateModelBound();
  m_character = new Node ("char node");
  //rootNode.attachChild(m_character);
  m_character.attachChild(StickMan);
  //m_character.updateWorldBound();
  m_character.setModelBound(new BoundingBox());
  m_character.updateModelBound();
  m_character.updateWorldBound();
  //m_character.attachChild(StickMan);
  rootNode.attachChild(m_character);
 
 
}catch (IOException e){
  System.out.println("Couldn't load the input file:" + e);
  e.printStackTrace();}
catch (java.lang.NullPointerException npe ) {
    npe.printStackTrace();
}

}


private void setupChaseCamera() {
    Vector3f targetOffset = new Vector3f();
  // targetOffset.y = ((BoundingBox) m_character.getWorldBound()).yExtent * 1.5f;
  targetOffset.y = 0.5f;
    HashMap<String, Object> props = new HashMap<String, Object>();
    props.put(ChaseCamera.PROP_STAYBEHINDTARGET, "true");
    chaser = new ChaseCamera(cam, m_character);
    chaser.setTargetOffset(targetOffset);
    chaser.setMinDistance(5);
    chaser.setMaxDistance(5);
}

    private void setupInput() {
        HashMap<String, Object> handlerProps = new HashMap<String, Object>();
        handlerProps.put(ThirdPersonHandler.PROP_DOGRADUAL, "true");
        handlerProps.put(ThirdPersonHandler.PROP_TURNSPEED,""+(1.0f * FastMath.PI));
        handlerProps.put(ThirdPersonHandler.PROP_LOCKBACKWARDS, "false");
        handlerProps.put(ThirdPersonHandler.PROP_CAMERAALIGNEDMOVE, "true");
        input = new ThirdPersonHandler(m_character, cam, handlerProps);
        input.setActionSpeed(100f);
    }
   
 
}

I found some help in other threads. These lines I add to my ChaseCamera:



                                  props.put(ChaseCamera.PROP_MAXDISTANCE, "0.1");

    props.put(ChaseCamera.PROP_MINDISTANCE, "0.1");

    props.put(ChaseCamera.PROP_DAMPINGK, "12");

    props.put(ChaseCamera.PROP_SPRINGK, "36");

Now it's behind him.



But there is still a problem, when I change the Max- and MinDistance there is no change in the distance to the StickMan. And the Camera is following a little bit on the left side behind the StickMan. Why? I've only changed the y-Offset. :?

 

Is your model z-up by chance?

Hi,



I don't realy understand waht you mean. I've created a stickman in Blender and imported it via xml-file to jME. This should be a placeholder for a more professionel character in future. Now I use a simple box as placeholder and this works with the offset.  :?



private void setupCharacter(){



        Box b = new Box("box", new Vector3f(), 2,5,2);

        b.setModelBound(new BoundingBox());

        b.updateModelBound();

        m_character = new Node("char node");

        scene.attachChild(m_character);

        m_character.attachChild(b);

        m_character.updateWorldBound();

        m_character.setLocalTranslation(40,-10,40); // position of the character

        m_character.setIsCollidable(true);

        TextureState ts = display.getRenderer().createTextureState();

        ts.setEnabled(true);

        ts.setTexture(

            TextureManager.loadTexture(

            TestThirdPersonController.class.getClassLoader().getResource(

            "jmetest/data/images/Monkey.tga"),

            Texture.MM_LINEAR,

            Texture.FM_LINEAR));

        m_character.setRenderState(ts);



}





private void setupChaseCamera() {

    Vector3f targetOffset = new Vector3f();

    targetOffset.y = ((BoundingBox) m_character.getWorldBound()).yExtent * 0.5f;

  // targetOffset.y = 0.5f;

 

    chaser = new ChaseCamera(cam, m_character);

    chaser.setTargetOffset(targetOffset);

    chaser.setMaxDistance(25);

    chaser.setMinDistance(25);

    chaser.setDampingK(12);

    chaser.setSpringK(36);

    chaser.setStayBehindTarget(true);



}