Relative movements

hi,



i needed advices, i'd like to make movements relative to the direction the camera is facing.

for example, i use keys W,A,S,D to move. W is used to go forward.

but W is alway moving in same direction… if i look behind me by rotating camera, and then press W, i will now move in same direction as before, thus making me move backward…



how can i make movement relative to the direction the camera is facing so the W key will alway make me move forward (the direction the cam is facing) … like it's done on almost all FPS out there…



here's the code i use so far:


                // if no collision do move
      if (oldData.getTargetTris().size()==0){
         
         lastPosition.set(b.getLocalTranslation());
         
         // the boolean at the end is for keypress repeat
         if (KeyBindingManager.getKeyBindingManager().isValidCommand("moveFwd", true))
         {
            b.getLocalTranslation().x += boxSpeed* timer.getTimePerFrame();
         }
         if (KeyBindingManager.getKeyBindingManager().isValidCommand("moveBwd", true))
         {
            b.getLocalTranslation().x -= boxSpeed* timer.getTimePerFrame();
         }
         if (KeyBindingManager.getKeyBindingManager().isValidCommand("moveLeft", true))
         {
            b.getLocalTranslation().z -= boxSpeed* timer.getTimePerFrame();
         }
         if (KeyBindingManager.getKeyBindingManager().isValidCommand("moveRight", true))
         {
            b.getLocalTranslation().z += boxSpeed* timer.getTimePerFrame();
         }         
      }
                // if collision go back to last known valid position
      if (oldData.getTargetTris().size()>0)
      {
         b.getLocalTranslation().set(lastPosition);
      }




tnx



I've kind of half-way sorted the problem, W and S keys now work.
if i press W key it will go forward according to the direction camera is facing.
same for S key .. going backward depending direction the camera is facing.
so far so good or so it look like, but
i can't figure how to make A and D key to strafe left or right depending direction camera is facing ?

here's the code so far


import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.jme.app.SimpleGame;
import com.jme.bounding.BoundingBox;
import com.jme.bounding.CollisionTree;
import com.jme.bounding.CollisionTreeManager;
import com.jme.input.KeyBindingManager;
import com.jme.input.KeyInput;
import com.jme.intersection.CollisionData;
import com.jme.intersection.CollisionResults;
import com.jme.intersection.TriangleCollisionResults;
import com.jme.math.FastMath;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.scene.Spatial;
import com.jme.scene.shape.Box;
import com.jme.util.export.binary.BinaryImporter;
import com.jmex.model.converters.FormatConverter;
import com.jmex.model.converters.ObjToJme;


public class HelloModelLoading extends SimpleGame {

   //private Node boxNode, mapNode;
   private Spatial b, m;
   private CollisionResults results;
   private CollisionData oldData;
   private Vector3f lastPosition;

   public static void main(String[] args) {
      HelloModelLoading app = new HelloModelLoading();
      app.setConfigShowMode(ConfigShowMode.AlwaysShow);
      Logger.getLogger("").setLevel(Level.SEVERE);
      app.start();
   }

   protected void simpleInitGame() {  

      //input = new InputHandler();
      CollisionTreeManager.getInstance().setTreeType(CollisionTree.Type.AABB);
      results = new TriangleCollisionResults();      

      URL model=HelloModelLoading.class.getClassLoader().getResource("data/test_01_02.obj");
      FormatConverter converter=new ObjToJme();
      converter.setProperty("mtllib",model);

      ByteArrayOutputStream BO=new ByteArrayOutputStream();
      try {

         //mapNode = new Node("map node");
         converter.convert(model.openStream(), BO);
         m=(Spatial) BinaryImporter.getInstance().load(new ByteArrayInputStream(BO.toByteArray()));
         m.setLocalScale(.1f);
         m.setModelBound(new BoundingBox());
         m.updateModelBound();


         //boxNode = new Node("box node");
         b = new Box("box", new Vector3f(0,5,0), 1, 1 ,1);
         b.setLocalScale(.4f);
         b.setModelBound(new BoundingBox());
         b.updateModelBound();

         rootNode.attachChild(b);
         rootNode.attachChild(m);

      } catch (Exception e) {   // Just in case anything happens
         System.out.println("Damn exceptions! O_o n" + e);
         e.printStackTrace();
         System.exit(0);
      }
      // change the direction camera is looking at
      cam.setAxes(new Vector3f(0,0,-1), new Vector3f(0,1,0), new Vector3f(1,0,0));

      KeyBindingManager.getKeyBindingManager().set("moveFwd", KeyInput.KEY_W);
      KeyBindingManager.getKeyBindingManager().set("moveBwd", KeyInput.KEY_S);
      KeyBindingManager.getKeyBindingManager().set("moveLeft", KeyInput.KEY_A);
      KeyBindingManager.getKeyBindingManager().set("moveRight", KeyInput.KEY_D);
      lastPosition = new Vector3f();
   }

   protected void simpleUpdate() {


      
      
      //put the cam at the box position
      cam.setLocation(new Vector3f(
            b.getLocalTranslation().getX(),
            b.getLocalTranslation().getY()+1,
            b.getLocalTranslation().getZ()
      ));

      results.clear();           
      b.findCollisions(rootNode, results);

      if (results.getNumber() <= 0) {
         System.out.printf("don't go out dammitn");
         System.exit(0);
      }
      oldData = results.getCollisionData(0);

      if (oldData.getTargetTris().size()==0){
         
         lastPosition.set(b.getLocalTranslation());      
         
         // the boolean at the end is for keypress repeat
         // Movement for W key (go forward depending the direction camera is facing)
         if (KeyBindingManager.getKeyBindingManager().isValidCommand("moveFwd", true))
         {
            b.getLocalTranslation().x += cam.getDirection().x * timer.getTimePerFrame();
            b.getLocalTranslation().z += cam.getDirection().z * timer.getTimePerFrame();
            
         }
         // Movement for S key (go backward depending the direction camera is facing)
         if (KeyBindingManager.getKeyBindingManager().isValidCommand("moveBwd", true))
         {
            b.getLocalTranslation().x -= cam.getDirection().x * timer.getTimePerFrame();
            b.getLocalTranslation().z -= cam.getDirection().z * timer.getTimePerFrame();
         }
         
         // Movement for A key (not working)
         if (KeyBindingManager.getKeyBindingManager().isValidCommand("moveLeft", true))
         {               
            b.getLocalTranslation().z -= cam.getDirection().z * timer.getTimePerFrame();            
         }
         
         // Movement for D key (not working)
         if (KeyBindingManager.getKeyBindingManager().isValidCommand("moveRight", true))
         {            
            b.getLocalTranslation().z += cam.getDirection().z * timer.getTimePerFrame();
         }         
      }

      if (oldData.getTargetTris().size()>0)
      {
         b.getLocalTranslation().set(lastPosition);
      }
   }
}

You can get a vector facing ideways from the camera by calculating the cross product of cam.getDirection() and Vector3f.UNIT_Y:


Vector3f sideways = cam.getDirection().cross(Vector3f.UNIT_Y);


BTW, http://www.euclideanspace.com/ is a great resource for anything related to 3d graphics math.

also, you can get a vector facing sideways from the camera from the CAMERA  :wink:



camera.getLeft() and camera.getUp() and camera.getDirection()

  • their negated evil twins (vec.multLocal(-1)) and you have all 6 possible vectors relative to the camera  :slight_smile:

:smiley:



By the way, you can also negate a vector using vec.negate and vec.negateLocal().


jjmontes said:

By the way, you can also negate a vector using vec.negate and vec.negateLocal().


which does nothing else  ;)

tnx ! i'll try

hevee said:

You can get a vector facing ideways from the camera by calculating the cross product of cam.getDirection() and Vector3f.UNIT_Y:


Vector3f sideways = cam.getDirection().cross(Vector3f.UNIT_Y);


BTW, http://www.euclideanspace.com/ is a great resource for anything related to 3d graphics math.


@hevee and others
thanks for the help!

i tryed getting the sideway vector by calcultating the cross product of the cam,
it mostly works , at least it's now much better and i can strafe left or right,
but there's a little problem left:
strafe works only when camera is facing world X axis.
if i turn my cam 90deg left or right and then try to strafe  it move veeery slowly. i have to turn the camera a bit toward world X axis to get more speed or turn it back completely toward X axis (i mean here:  X or -X (looking forward or backward the player)) to have strafe to work normaly.

here's the code i used:


               
      if (oldData.getTargetTris().size()==0){      // if *no* collision then do:
         
         lastPosition.set(b.getLocalTranslation());   // first save last position
         
         // the boolean at the end is for keypress repeat
         if (KeyBindingManager.getKeyBindingManager().isValidCommand("moveFwd", true))
         {
            //b.getLocalTranslation().x += boxSpeed* timer.getTimePerFrame();
            b.getLocalTranslation().x += cam.getDirection().x * timer.getTimePerFrame();
            b.getLocalTranslation().z += cam.getDirection().z * timer.getTimePerFrame();
            
         }
         if (KeyBindingManager.getKeyBindingManager().isValidCommand("moveBwd", true))
         {
            b.getLocalTranslation().x += cam.getDirection().x * timer.getTimePerFrame();
            b.getLocalTranslation().z += cam.getDirection().z * timer.getTimePerFrame();
         }
         if (KeyBindingManager.getKeyBindingManager().isValidCommand("moveLeft", true))
         {
                            //  strafe left  (partialy works depending if the cam faces world X or not)   
             Vector3f sideways = cam.getDirection().cross(Vector3f.UNIT_Y);
             b.getLocalTranslation().z -= sideways.z * timer.getTimePerFrame();

         }
         if (KeyBindingManager.getKeyBindingManager().isValidCommand("moveRight", true))
         {
                            //  strafe right  (partialy works depending if the cam faces world X or not)
             Vector3f sideways = cam.getDirection().cross(Vector3f.UNIT_Y);
             b.getLocalTranslation().z += sideways.z * timer.getTimePerFrame();
         }         
      }

               
      if (oldData.getTargetTris().size()>0)          // if collision happened then do:
      {
         b.getLocalTranslation().set(lastPosition);
      }



if needed the whole code (only one small class) can be seen here: http://code.google.com/p/spaceweasel/source/browse/trunk/druaga3/src/HelloModelLoading.java?r=102

the cross product is not normalized … call vector.normalize() or .normalizeLocal() so it will be a normalized vector.



that vector can then be multiplied by the speed of your movement and it will always strafe with the same speed.

dhdd said:

the cross product is not normalized ... call vector.normalize() or .normalizeLocal() so it will be a normalized vector.

that vector can then be multiplied by the speed of your movement and it will always strafe with the same speed.


@dhdd

tnx but, i think it's not about variable speed, it's about axis..
when i'm (the camera) facing an axis other than X (say if i look left) the strafe don't work.
as soon as i rotate even just a bit the camera toward X strafe start to works progressively..
i made a webstart :  http://keisangi.free.fr/dungeon/dungeon.jnlp
(i have a problem with texture, they couldn't be found on the webstart version i dunno why yet.
so, there's only the default "missing  texture" displayed. but the rest works ok, you can test moving around in the dungeon)
you can move using key W,A,S,D and mouse look, as in most FPS.
you'll see what i mean about strafe left or right ...try facing the wall on your sides and press A or D.


full code is there:  http://code.google.com/p/spaceweasel/source/browse/trunk/druaga3/src/HelloModelLoading.java


keisangi, please dont get me wrong, but if you want help and get help you have to listen to the people that actually ARE helping you.



try this:


         if (KeyBindingManager.getKeyBindingManager().isValidCommand("moveLeft", true))
         {
             Vector3f sideways = cam.getLeft().normalize();
             b.getLocalTranslation().z -= sideways.z * timer.getTimePerFrame();

         }
         if (KeyBindingManager.getKeyBindingManager().isValidCommand("moveRight", true))
         {
             Vector3f sideways = cam.getLeft().mult(-1).normalizeLocal();
             b.getLocalTranslation().z += sideways.z * timer.getTimePerFrame();
         }         

dhdd said:


try this:


         if (KeyBindingManager.getKeyBindingManager().isValidCommand("moveLeft", true))
         {
             Vector3f sideways = cam.getLeft().normalize();
             b.getLocalTranslation().z -= sideways.z * timer.getTimePerFrame();

         }
         if (KeyBindingManager.getKeyBindingManager().isValidCommand("moveRight", true))
         {
             Vector3f sideways = cam.getLeft().mult(-1).normalizeLocal();
             b.getLocalTranslation().z += sideways.z * timer.getTimePerFrame();
         }         




i tryed and it doesn't work..
it does roughly the same as the previous code.

*update:
to be clear it work only when facing straight forward or backward.
as soon as you look around ,  and try to strafe, it doesn't work as expected.
the best to see the problem is to look at the walls on your side.

like this:
when the webstart run, do a 90deg rotation to look at the wall on your left or your right and try to strafe:  it doesn't work.
then rotate back to normal (facing forward) and try to strafe:  it works.
so it does works *only* when looking toward 2 directions: forward and backward:  i think it's because it's the same axis..

you can test the webstart to see what i'm poorly trying to explain.

anyway thanks for trying to help !







i got it working now  :)
thanks a lot for all the help!

webstart updated: http://keisangi.free.fr/dungeon/dungeon.jnlp
(texture are still missing, but the movement are ok now)

and the final code:


import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.jme.app.SimpleGame;
import com.jme.bounding.BoundingBox;
import com.jme.bounding.CollisionTree;
import com.jme.bounding.CollisionTreeManager;
import com.jme.input.KeyBindingManager;
import com.jme.input.KeyInput;
import com.jme.intersection.CollisionData;
import com.jme.intersection.CollisionResults;
import com.jme.intersection.TriangleCollisionResults;
import com.jme.math.Vector3f;
import com.jme.scene.Spatial;
import com.jme.scene.shape.Box;
import com.jme.util.export.binary.BinaryImporter;
import com.jmex.model.converters.FormatConverter;
import com.jmex.model.converters.ObjToJme;


public class HelloModelLoading extends SimpleGame {

   //private Node boxNode, mapNode;
   private Spatial b, m;
   private CollisionResults results;
   private CollisionData oldData;
   private float playerSpeed=3f;
   private Vector3f lastPosition;


   public static void main(String[] args) {
      HelloModelLoading app = new HelloModelLoading();
      app.setConfigShowMode(ConfigShowMode.AlwaysShow);
      Logger.getLogger("").setLevel(Level.SEVERE);
      app.start();
   }

   protected void simpleInitGame() {  

      //input = new InputHandler();
      CollisionTreeManager.getInstance().setTreeType(CollisionTree.Type.AABB);
      results = new TriangleCollisionResults();      

      URL model=HelloModelLoading.class.getClassLoader().getResource("test_01_01.obj");
      FormatConverter converter=new ObjToJme();
      converter.setProperty("mtllib",model);

      ByteArrayOutputStream BO=new ByteArrayOutputStream();
      try {

         //mapNode = new Node("map node");
         converter.convert(model.openStream(), BO);
         m=(Spatial) BinaryImporter.getInstance().load(new ByteArrayInputStream(BO.toByteArray()));
         m.setLocalScale(.1f);
         m.setModelBound(new BoundingBox());
         m.updateModelBound();


         //boxNode = new Node("box node");
         b = new Box("box", new Vector3f(0,5,0), 1, 1 ,1);
         b.setLocalScale(.4f);
         b.setModelBound(new BoundingBox());
         b.updateModelBound();

         rootNode.attachChild(b);
         rootNode.attachChild(m);

      } catch (Exception e) {   // Just in case anything happens
         System.out.println("Damn exceptions! O_o n" + e);
         e.printStackTrace();
         System.exit(0);
      }
      
      // change the direction camera is looking at
      cam.setAxes(new Vector3f(0,0,-1), new Vector3f(0,1,0), new Vector3f(1,0,0));

      KeyBindingManager.getKeyBindingManager().set("moveFwd", KeyInput.KEY_W);
      KeyBindingManager.getKeyBindingManager().set("moveBwd", KeyInput.KEY_S);
      KeyBindingManager.getKeyBindingManager().set("moveLeft", KeyInput.KEY_A);
      KeyBindingManager.getKeyBindingManager().set("moveRight", KeyInput.KEY_D);
      lastPosition = new Vector3f();
   }

   protected void simpleUpdate() {
   
      //put the cam at the box position
      cam.setLocation(new Vector3f(
            b.getLocalTranslation().getX(),
            b.getLocalTranslation().getY()+1,
            b.getLocalTranslation().getZ()
      ));

      results.clear();           
      b.findCollisions(rootNode, results);

      if (results.getNumber() <= 0) {
         System.out.printf("don't go out dammitn");
         System.exit(0);
      }
      oldData = results.getCollisionData(0);

      if (oldData.getTargetTris().size()==0){
         
         lastPosition.set(b.getLocalTranslation());
         
         // the boolean at the end is for keypress repeat
         if (KeyBindingManager.getKeyBindingManager().isValidCommand("moveFwd", true))
         {
            b.getLocalTranslation().x += cam.getDirection().x * playerSpeed * timer.getTimePerFrame();
            b.getLocalTranslation().z += cam.getDirection().z * playerSpeed * timer.getTimePerFrame();
            
         }
         if (KeyBindingManager.getKeyBindingManager().isValidCommand("moveBwd", true))
         {
            b.getLocalTranslation().x -= cam.getDirection().x * playerSpeed * timer.getTimePerFrame();
            b.getLocalTranslation().z -= cam.getDirection().z * playerSpeed * timer.getTimePerFrame();
         }
         if (KeyBindingManager.getKeyBindingManager().isValidCommand("moveLeft", true))
         {   
             Vector3f sideways = cam.getLeft();
             b.getLocalTranslation().x += sideways.x * playerSpeed * timer.getTimePerFrame();
             b.getLocalTranslation().z += sideways.z * playerSpeed * timer.getTimePerFrame();

         }
         if (KeyBindingManager.getKeyBindingManager().isValidCommand("moveRight", true))
         {
             Vector3f sideways = cam.getLeft();
             b.getLocalTranslation().x -= sideways.x * playerSpeed * timer.getTimePerFrame();
             b.getLocalTranslation().z -= sideways.z * playerSpeed * timer.getTimePerFrame();
         }         
      }

      if (oldData.getTargetTris().size()>0)
      {
         b.getLocalTranslation().set(lastPosition);
      }
   }
}




i guess that wont work in all cases either.



try it like that



Vector3f sideways = cam.getLeft();
b.getLocalTranslation().add(sideways.normalize().mult(speed));