Firing bullet from dynamic physic node location to mouse position

Hello,



I am trying to fire a bullet from my tank dynamic node to the mouse position for the last 7 hours now,  but the bullet is always flying in another direction. I attached a screen shot of the game. The red X marks the position of the mouse in the game. Don't know why the mouse is not visible in the screen shot. Here is the code I am using to create and move the bullet. The worldCoords are coming from the input handler code below.



   public void fireBullet(Vector3f worldCoords)
   {
      Sphere bullet = new Sphere("bullet" + numBullets++, 8, 8, .1f);
      bullet.setModelBound(new BoundingSphere());
      bullet.updateModelBound();
      rootNode.attachChild(bullet);
      /** Move bullet to the camera location */
      
      Vector3f source = new Vector3f(canon.getLocalTranslation().clone());
      bullet.getLocalTranslation().set(source);
      bullet.setRenderState(bulletMaterial);
      bullet.updateGeometricState(0, true);
      
      Vector3f target = new Vector3f(worldCoords.getX(),0,worldCoords.getY());
      target = target.subtract(source);
      target.setY(0);
      
      bullet.addController(new BulletMover(bullet,target));
      bullet.updateRenderState();
   }   
   class BulletMover extends Controller {
       private static final long serialVersionUID = 1L;
      TriMesh bullet;
      Vector3f direction;
      float speed = 10;
      float lifeTime = 3;

      BulletMover(TriMesh bullet, Vector3f direction) {
         this.bullet = bullet;
         this.direction = direction;
         this.direction.normalizeLocal();
      }

      public void update(float time) {
         lifeTime -= time;
         /** If life is gone, remove it */
         if (lifeTime < 0) {
            rootNode.detachChild(bullet);
            bullet.removeController(this);
            return;
         }
         /** Move bullet */
         Vector3f bulletPos = bullet.getLocalTranslation();
         float y = bulletPos.getY();
         Vector3f tmp = direction.mult(time * speed);
         bulletPos.addLocal(tmp);
         bulletPos.setY(y);
         bullet.setLocalTranslation(bulletPos);
         /** Does the bullet intersect with target? */
//         if (bullet.getWorldBound().intersects(target.getWorldBound())) {
//                lifeTime = 0;
//         }
      }
   }



Part of the input handler


   public class FireAction extends InputAction
   {

      public FireAction()
      {   

      }
      public void performAction(InputActionEvent evt)
      {
         if (evt.getTriggerPressed())         {
         //vNode.fireBullet(new Vector3f(Mouse.getX(),0.0f, Mouse.getY()));
            Vector2f screenPos = new Vector2f();
            screenPos.set(Mouse.getX(), 0);
            Vector3f worldCoords = DisplaySystem.getDisplaySystem().getWorldCoordinates(screenPos, Mouse.getY());
            System.out.println("x: " + worldCoords.getX() + " Y: " + worldCoords.getZ());
            
         vNode.fireBullet(worldCoords);          
         }
      }
   }


The floor of the game is set between the axis x and z.

With kind regards

Ineluki

I didn't look thru all the source but this looks wrong:

Vector3f target = new Vector3f(worldCoords.getX(),0,worldCoords.getY());

as a vector is (x,y,z)



and in my code, i do this to get the world coordinates of the mouse

Vector2f screenPos = new Vector2f();

screenPos.set(mouseManager.getMousePosition().clone());



Vector3f worldCoords = display.getWorldCoordinates(screenPos, zPos);



and by the way, length of a vector is always positive, and dividing a vector by it's length is what you do when normalizing

the normal mouse coordinates start at the bottom left corner of the window (0:0).

My tank starts at the position Vector3f(6,1,5) in the normal mouse coordinates that is x: 276 Y: 399



System.out.println("x: " + Mouse.getX() + " Y: " + Mouse.getY());





@Haladria:



I get the world coordinates in the input handler:



screenPos.set(Mouse.getX(), 0);

Vector3f worldCoords = DisplaySystem.getDisplaySystem().getWorldCoordinates(screenPos, Mouse.getY());



y has to be used as z coordinate because the level is set between the x and z axis.

The correct solution would be to shot a ray and check the point it hits your game board.



this is how you make such a ray:


Vector2f screenPos = new Vector2f();
// Get the position that the mouse is pointing to
screenPos.set(mouseManager.getMousePosition().clone());

// Get the world location of that X,Y value
Vector3f worldCoords = display.getWorldCoordinates(screenPos, 1.0f);
// Create a ray starting from the camera, and going in the direction
// of the mouse's location
Ray mouseRay = new Ray(camera.getLocation(), worldCoords.subtractLocal(camera.getLocation()));
mouseRay.getDirection().normalizeLocal();

I think its because you have target = target.subtract(source); instead of target = target.add(source); If its going in the exact opposite direction then you could always just multiply the direction vector by a negative scalar ie -1.  Not sure if that helps.

Ok, I should have mentioned that the bullet is always flying in the same direction no matter where my mouse is. I think the problem is the mouse input. I made a system out of the mouse coordinates after I translated them into world coordinates, but the result looks like this:



x: -3.9321138E-5 Y: 0.0016851941

x: -0.0026162686 Y: 0.002843772



when I set the target manually to a certain point like Vector3f(6,0,6) it is working. All bullets then fly to this position no matter where my source(tank) is on the map.

Why not just use the actual mouse coordinates and subtract the tank screen coordinates?  Instead of converting the mouse coordinates just add the difference between the tanks start position and the top left of the screen to the tanks position.

Thx a lot Haladria it is nearly working now!

Here is the code I used:



Vector2f screenPos = new Vector2f();
            screenPos.set(Mouse.getX(),Mouse.getY());
            Vector3f target = DisplaySystem.getDisplaySystem().getWorldCoordinates(screenPos,0);

            Vector3f source = DisplaySystem.getDisplaySystem().getRenderer().getCamera().getLocation();
            Vector3f direction =  target.subtract(source);
            Ray mouseRay = new Ray(source, direction);
            mouseRay.getDirection().normalizeLocal();
               pr.clear();
               vNode.getRootNode().findPick(mouseRay, pr);
               if ( pr.getNumber() == 1 )
               {
                  Vector3f targetElement = pr.getPickData(0).getTargetMesh().getParentGeom().getLocalTranslation();
                  String name = pr.getPickData(0).getTargetMesh().getParentGeom().getName();
                  
                  System.out.println("Name: " + name + " X: " + targetElement.getX() + " Y: " + targetElement.getY() + " Z: " + targetElement.getZ());
                  vNode.fireBullet(targetElement);       
               }



But at the moment I am only able to get the LocalTranslation of the floor element the ray is going through. Unfortunately the floor elements have a width and height of 1 so I do not have the exact  position of the mouse. Is there a way to get the exact coordinates of the point where the ray is going through the floor? Or do I have to make more but smaller floor elements?

With kind regards

Ineluki

I don't remember how you actually get the intersection point when doing picking.



With some math, you could just do this (if you only bother about where on the flat floor you click):

You could check collision/intersection between the ray and the x-z plane (that will be the plane with normal (0,1,0) and constant 0). I assume your floor is at y=0, otherwise change the constant?


Plane plane = new Plane();
plane.setNormal(Vector3f.UNIT_Y.clone());
Vector3f intersection = new Vector3f();
mouseRay.intersectsWherePlane(plane, intersection);
// now intersection holds the coordinates

Thank a lot Haladria that is exactly what I was looking for!



And it works :slight_smile:


Good  :slight_smile: