[SOLVED]Figuring out an angle

This is kind of a follow-up on a previous I did:



http://www.jmonkeyengine.com/jmeforum/index.php?topic=7933.0



I was able to solve that issue by using slerp, however; I'm having trouble finding out the angle between where a node is pointed and a location to where it wants to go. There are a couple threads on this already:



http://www.jmonkeyengine.com/jmeforum/index.php?topic=6383.0



…but I must be doing something wrong.



What I'd like is to always have where the ship is facing to be zero degrees, and increase to 360 clockwise around it. This is to support implementing a ship lean function that I have. If the angle is from 0-180, lean right. If it's from 180-360, lean left. This is what I have so far, and for some reason it's not giving me the angles that I'm expecting. the onButton is where I'm doing the angle calculation.









import com.jme.image.Texture;
import com.jme.input.AbsoluteMouse;
import com.jme.input.InputHandler;
import com.jme.input.MouseInputListener;
import com.jme.math.FastMath;
import com.jme.math.Matrix3f;
import com.jme.math.Plane;
import com.jme.math.Quaternion;
import com.jme.math.Ray;
import com.jme.math.Triangle;
import com.jme.math.Vector2f;
import com.jme.math.Vector3f;
import com.jme.scene.Controller;
import com.jme.scene.Node;
import com.jme.scene.state.AlphaState;
import com.jme.scene.state.TextureState;
import com.jme.system.DisplaySystem;
import com.jme.util.TextureManager;

public class MouseClickMove implements MouseInputListener {

   protected static DriftAction drift;

   protected Ship ship = proto.getShip();
   protected Ship enemy = proto.getEnemy();
   protected Node scene = proto.getScene();
   protected InputHandler input = proto.getInput();
   protected AbsoluteMouse am;
   protected shipMoveController shipMove;
   protected float modifier;
   

   public void initializeMouseMove() {
      setupMouse();
      shipMove = new shipMoveController(ship);
      shipMove.setSpeed(ship.getVelocity());
      ship.addController(shipMove);

   }

   private void setupMouse() {
      // mouse stuff
      // Create a new mouse. Restrict its movements to the display screen.
      am = new AbsoluteMouse("The Mouse", DisplaySystem.getDisplaySystem()
            .getWidth(), DisplaySystem.getDisplaySystem().getHeight());
      // Get a picture for my mouse.
      final TextureState mCursor = DisplaySystem.getDisplaySystem()
            .getRenderer().createTextureState();
      final URL cursorLoc = CakeProto.class.getClassLoader().getResource(
            "jmetest/data/cursor/cursor1.png");
      final Texture t = TextureManager.loadTexture(cursorLoc,
            Texture.MM_LINEAR, Texture.FM_LINEAR);
      mCursor.setTexture(t);
      am.setRenderState(mCursor);

      // Make the mouse's background blend with what's already there
      final AlphaState as = DisplaySystem.getDisplaySystem().getRenderer()
            .createAlphaState();
      as.setBlendEnabled(true);
      as.setSrcFunction(AlphaState.SB_SRC_ALPHA);
      as.setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA);
      as.setTestEnabled(true);
      as.setTestFunction(AlphaState.TF_GREATER);
      am.setRenderState(as);

      // Get the mouse input device and assign it to the AbsoluteMouse
      // Move the mouse to the middle of the screen to start with
      am.setLocalTranslation(new Vector3f(DisplaySystem.getDisplaySystem()
            .getWidth() / 2,
            DisplaySystem.getDisplaySystem().getHeight() / 2, 0));
      // Assign the mouse to an input handler
      am.registerWithInputHandler(input);

      // Attach Children
      scene.attachChild(am);
   }

   @Override
   public void onButton(final int button, final boolean pressed, final int x,
         final int y) {

      final int isPressed = button;

      // System.out.println("focus is " + InGameUI2.isFocus());

      if ((isPressed == 0) && (InGameUI.isFocus() == false)) {
         final Plane p1 = new Plane();
         final Vector3f t1a = new Vector3f(0, 0, 0); // point a on Triangle
         // 1;
         final Vector3f t1b = new Vector3f(1, 0, 0); // point b on Triangle
         // 1;
         final Vector3f t1c = new Vector3f(0, 0, 1); // point c on Triangle
         // 1;

         final Triangle t1 = new Triangle(t1a, t1b, t1c);
         p1.setPlanePoints(t1);

         final Vector2f screenPos = new Vector2f();
         // Get the position that the mouse is pointing to
         screenPos.set(am.getHotSpotPosition().x, am.getHotSpotPosition().y);
         // Get the world location of that X,Y value
         final Vector3f worldCoords = DisplaySystem.getDisplaySystem()
               .getWorldCoordinates(screenPos, 0);
         final Vector3f worldCoords2 = DisplaySystem.getDisplaySystem()
               .getWorldCoordinates(screenPos, 1);
         final Vector3f direction = worldCoords2.subtractLocal(worldCoords)
               .normalizeLocal();
         final Vector3f loc1 = new Vector3f();
         final Ray mouseRay = new Ray(worldCoords, direction);

         final boolean intersection1 = mouseRay.intersectsWherePlane(p1,
               loc1);
         
         Vector3f shipDirection = ship.getWorldRotation().getRotationColumn(2);
         //direction.normalizeLocal();
         
         Vector3f toDirection = direction.subtract(ship.getWorldTranslation());
            toDirection.normalizeLocal();
         
         shipDirection.cross( toDirection, Vector3f.UNIT_Y );
           Vector3f.UNIT_Y.normalizeLocal();
         
         
         float rotationAngle = FastMath.RAD_TO_DEG*(shipDirection.angleBetween(toDirection));
         
         if (rotationAngle > 0 && rotationAngle < 180) {
            //lean right
            modifier = 1;
         } else if (rotationAngle > 180 && rotationAngle < 359) {
            //lean left
            modifier = -1;
         } else {
            modifier = 0;
         }
         
         System.out.println(rotationAngle);
         
         if (intersection1) {
            shipMove.setDesiredLocation(loc1, modifier);
         }

         drift = new DriftAction(ship);

      } else {
         return;
      }

   }

   @Override
   public void onMove(final int delta, final int delta2, final int newX,
         final int newY) {
      // TODO Auto-generated method stub

   }

   @Override
   public void onWheel(final int wheelDelta, final int x, final int y) {
      // TODO Auto-generated method stub

   }

   private static class shipMoveController extends Controller {
      private static final long serialVersionUID = 1L;

      private final Ship ship;
      private Vector3f desiredLocation;
      private boolean moving;
      private float modifier;
      private final Vector3f upAxis = new Vector3f(0, 1, 0);
      private final Vector3f temp = new Vector3f();
      
      public shipMoveController(final Ship ship) {
         this.ship = ship;
      }

      public void setDesiredLocation(final Vector3f location, float modifier) {
         this.desiredLocation = location;
         this.modifier = modifier;
         this.moving = true;
      }

      public Vector3f getDesiredLocation() {
         return desiredLocation;
      }

      @Override
      public void update(final float time) {

         if (!moving) {
            return;
         }
         
         
         final Vector3f directional = desiredLocation.subtract(ship
               .getLocalTranslation(), temp);
         //directional.normalize();      

         final float length = directional.length();
         if (length < 5) { // if it's around x units
            ship.deccelerate(time);
            moving = false;
            return;
         }

         float shipFlyDistance = ship.getVelocity() * time;
         if (shipFlyDistance > length) {
            shipFlyDistance = length;
         }
         directional.multLocal(shipFlyDistance / length);

         ship.accelerate(time);
         ship.updateWorldVectors();
         Quaternion start = new Quaternion(ship.getLocalRotation());
         ship.getLocalRotation().lookAt(directional, upAxis);
         ship.getLocalRotation().slerp(start, 0.99f);
         ship.getLocalTranslation().addLocal(directional);
         ship.setRotateOn(modifier);
      }

   }

}

1 Like

Vector mathematics: http://www.sunybroome.edu/~biegen_j/phys1/examples/MOD2_2EX1.HTM

Yeah Trussel…I've tried various vector math implementations (…the code above is my recent attempt…) and beleive me when I say I have lots of math books here :wink:



Don't know…I must be missing something as I figure that at the end of the day, the angleBetween function would be getting me the angle that I was looking for. I think I've been looking at this problem for so long that the obvious answer eludes me.

I can't grasp exactly what you want from what you have said so far. I'm not interested in the code at this point just what you are trying to accomplish.



Is this "ship" moving between any two points in 3d? What is the angle you are talking about is the ship moving along a xz-plane or any other plane and the angle is the direction in that plane?



What is the path your ship is moving along? A straight line between two given points?


Hey Obi,



So what I've got is a ship in the xz-plane (no y-axis movement at the moment). The user selects a point along the xz-plane where they want the ship to move with the mouse. Right now, I have the ship moving and turning quite smoothly…so that's not an issue. What I'd like to do is have the ship tilt in the direction of movement so that it looks a bit more natural a la the Flag tutorial.



The pseudo code would go something like this:


  • if the angle is between 0-180 degrees, tilt right
  • if the angle is between 180-360 degrees, tilt left.



    The "angle" I would like is the angle between the direction the ship is currently pointing to where the user clicked in space. I'm assuming that 0 degrees is in front of the ship, 180 is behind…etc etc.



    D

vector3f anglebetween method will only give you the "shortest angle" between two vectors. between 0-180 that is. one simple hack is to do a cross product between the two as well, and see what direction it's pointing. in one dir, use the angle directly. in the other, use 360 - angle…

Oki if both your ship direction and the direction to the destination is in the same xz-plane then you can use Vector3f's angleBetween. But notice that this only gives an angle between 0-180 since the dot product used in angleBetween don't care if the angle is to the right or left of your ship.



You could use the crossproduct between your direction and your destination to determine that. The cross will point in either positive or negative y direction. Depending on the sign of the crossproduct y value you know if it is a left or a right turn.



So that will give you left or right turn and angleBetween gives you the size of the turn which I guess might effect how much you tilt your ship.



Hope that was what you where after?



Edit: damn MrCoder beat me to the punch :slight_smile:

1 Like

7 minutes faster man!  XD

/Darren smacks his head.



Coder/Obi…that cross-product solution sounds perfect. Sucks that I'm at work and can't give it a try. It makes so much sense and it proves my theory that I've stared at the code too much for this one.



:slight_smile:



I'll try that out tonight and let you know how it goes.



Thanks very much.

It works guys. Just got some tweaking to do but I think I'm there.



Thanks again. Very supportive community and I appreciate it

1 Like