JMonkey - 以十字准线方向射击

时间:2013-05-22 23:45:51

标签: java 3d jmonkeyengine aim

我怎样才能朝十字准线指向的方向拍摄?

使用JMonkey引擎,我正在创建一个游戏,我需要一艘船来射击其他船只。

因此,我根据用户输入创建了可以在屏幕上(向上,向下,向左,向右)移动的十字准线,因此用户可以瞄准某个地方。

现在我需要从我的船上射出一个大炮,朝着十字线的方向站立。

我怎样才能在十字准线指向的地方拍摄?

2 个答案:

答案 0 :(得分:3)

您可以通过以下方式获取相机方向:

directionXYZ=cam.getDirection(); //Vector3f form

可以从以下位置获得职位:

positionXYZ=cam.getLocation(); //Vector3f

你可以进行光线投射:

 Ray ray = new Ray(directionXYZ, positionXYZ);

然后可以收集碰撞数据:

shootables.collideWith(ray, results)

其中可拍摄的是“节点”。

最后,检查一下你想要的东西:

 for (int i = 0; i < results.size(); i++) {
      // For each hit, we know distance, impact point, name of geometry.
      float dist = results.getCollision(i).getDistance();
      Vector3f pt = results.getCollision(i).getContactPoint();
      String hit = results.getCollision(i).getGeometry().getName();
      System.out.println("* Collision #" + i);
      System.out.println("  You shot " + hit + " at " + pt + ", " + dist + " wu away.");
    }

取自jmonkey wiki

答案 1 :(得分:1)

我对这个问题的解读是,目的不是拍摄相机所朝向的位置,而是光标(不在屏幕中央)指向的位置。

这可以使用cam.getWorldCoordinates(screenPosition, zDepth);命令来实现,这将返回空间中的3D点,该点将最终位于屏幕上的screenPosition点。因此,如果我们在zDepth为零时创建一个点,在zDepth为1时创建一个点,我们可以创建一个从光标位置向外传播的光线,这样就可以选择光标“过度”的任何东西。 screenPosition是从窗口左下角开始的像素

使用此技术的示例程序如下,基于hello picking的第二部分。

在我的例子中,使用键盘(H,J,K,U)移动光标,但也可以使用鼠标点击(但我使用鼠标环顾四周)

import com.jme3.app.SimpleApplication;
import com.jme3.collision.CollisionResults;
import com.jme3.font.BitmapText;
import com.jme3.input.KeyInput;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Ray;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.shape.Box;

public class Main extends SimpleApplication {

    public static KeyBindings keyBindings;
    public Vector2f cursorPosition=new Vector2f(100,100);
    public Node shootables=new Node();

    public Node crossHairNode=new Node();

    public static void main(String[] args) {
        Main app = new Main();
        app.start();
    }

    @Override
    public void simpleInitApp() {
        //bind keys to move cursor
        keyBindings=new KeyBindings(inputManager); //for managing keystrokes
        keyBindings.registerKeyBinding(KeyInput.KEY_SPACE, "fire");
        keyBindings.registerKeyBinding(KeyInput.KEY_U, "up"); 
        keyBindings.registerKeyBinding(KeyInput.KEY_J, "down");
        keyBindings.registerKeyBinding(KeyInput.KEY_H, "left");
        keyBindings.registerKeyBinding(KeyInput.KEY_K, "right");

        initGui();

        Box b = new Box(Vector3f.ZERO, 2, 2, 2);
        Geometry geom = new Geometry("BigBox", b);

        Box b2 = new Box(Vector3f.ZERO, 1, 1, 1);
        Geometry geom2 = new Geometry("SmallBox", b2);
        geom2.setLocalTranslation(3, 0, 3);


        Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        mat.setColor("Color", ColorRGBA.Blue);
        geom.setMaterial(mat);
        geom2.setMaterial(mat);
        rootNode.attachChild(shootables);

        shootables.attachChild(geom);
        shootables.attachChild(geom2);
    }

    @Override
    public void simpleUpdate(float tpf) {

        updateCrossHairs();

        if (keyBindings.getBinding("fire").hasBecomeTrueSinceLastAccess()){
            CollisionResults results = new CollisionResults();

            Vector3f cursor3dLocation = cam.getWorldCoordinates(
                new Vector2f(cursorPosition.x, cursorPosition.y), 0f).clone();
            Vector3f dir = cam.getWorldCoordinates(
                new Vector2f(cursorPosition.x, cursorPosition.y), 1f).subtractLocal(cursor3dLocation).normalizeLocal();
            Ray ray = new Ray(cursor3dLocation, dir);
            shootables.collideWith(ray, results);

            if (results.size()>0){
                resultsText.setText("Hit: " + results.getClosestCollision().getGeometry().getName());
                resultsText.setLocalTranslation(settings.getWidth()-resultsText.getLineWidth(),resultsText.getLineHeight(), 0);
            }else{
                resultsText.setText("Missed");
                resultsText.setLocalTranslation(settings.getWidth()-resultsText.getLineWidth(),resultsText.getLineHeight(), 0);                
            }

        }



    }

    private void updateCrossHairs(){
        if (keyBindings.getBinding("up").getValue()==true){
            cursorPosition.y+=1;
        }
        if (keyBindings.getBinding("down").getValue()==true){
            cursorPosition.y+=-1;
        }

        if (keyBindings.getBinding("left").getValue()==true){
            cursorPosition.x+=-1;
        }
        if (keyBindings.getBinding("right").getValue()==true){
            cursorPosition.x+=+1;
        }

        crossHairNode.setLocalTranslation(cursorPosition.x - crossHair.getLineWidth()/2,cursorPosition.y + crossHair.getLineHeight()/2, 0);

    }

    BitmapText crossHair;
    BitmapText instructions;
    BitmapText resultsText;

    private void initGui() {
        setDisplayStatView(false);
        guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
        crossHair = new BitmapText(guiFont, false);
        crossHair.setSize(guiFont.getCharSet().getRenderedSize() * 2);
        crossHair.setText("+"); // crosshairs

        crossHairNode.setLocalTranslation(cursorPosition.x - crossHair.getLineWidth()/2,cursorPosition.y + crossHair.getLineHeight()/2, 0);


        guiNode.attachChild(crossHairNode);
        crossHairNode.attachChild(crossHair);

        instructions= new BitmapText(guiFont, false);
        instructions.setSize(guiFont.getCharSet().getRenderedSize());
        instructions.setText("Move cross hairs with U,H,J,K keys, fire with space \n (WSAD moves camera position and look with mouse)"); 
        instructions.setLocalTranslation(0, settings.getHeight(), 0);

        guiNode.attachChild(instructions);

        resultsText= new BitmapText(guiFont, false);
        resultsText.setSize(guiFont.getCharSet().getRenderedSize());
        resultsText.setText("Press Space to fire"); 
        resultsText.setLocalTranslation(settings.getWidth()-resultsText.getLineWidth(),resultsText.getLineHeight(), 0);

        guiNode.attachChild(resultsText);



   }

    @Override
    public void simpleRender(RenderManager rm) {
        //TODO: add render code
    }
}

键绑定,仅用于控制光标移动:

import com.jme3.input.InputManager;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import java.util.ArrayList;
import java.util.Locale;

public class KeyBindings  implements ActionListener{

    private InputManager inputManager;
    private ArrayList<String> bindingString=new ArrayList<String>(100);
    private ArrayList<KeyBinding> binding=new ArrayList<KeyBinding>(100);

    public KeyBindings(InputManager inputManager){
        this.inputManager=inputManager;
    }

    public void registerKeyBinding(int key,String bindingName){
        bindingName=preprocess(bindingName);
        inputManager.addMapping( bindingName, new KeyTrigger(key));
        inputManager.addListener(this,  bindingName);

        binding.add(new KeyBinding());
        bindingString.add(bindingName);
    }

   public void registerMouseBinding(int button,String bindingName){
        bindingName=preprocess(bindingName);
        inputManager.addMapping( bindingName, new MouseButtonTrigger(button));
        inputManager.addListener(this,  bindingName);

        binding.add(new KeyBinding());
        bindingString.add(bindingName);
    }


    public KeyBinding getBinding(String bindingName){
        //get which binding we're after
        bindingName=preprocess(bindingName);

        int index=bindingString.indexOf(bindingName);

        if (index!=-1){
            return binding.get(index);
        }else{
            return null;
        }
    }

    public void onAction(String  bindingName, boolean isPressed, float tpf) {
        bindingName=preprocess(bindingName);

        //get which binding we're after
        int index=bindingString.indexOf(bindingName);

        if (index!=-1){
            binding.get(index).setValue(isPressed);
        }
    }


    private String preprocess(String string){
        return string.toUpperCase();
    }

}


public class KeyBinding {

    private boolean value;
    private boolean changedSinceLastAccess; //to avoid multiclicks etc
    private boolean valueTrueSinceLastAccess;


    public void setValue(boolean value){
         this.value=value;
         changedSinceLastAccess=true;

         if (value==true){
             valueTrueSinceLastAccess=true;
         }
    }

    public boolean hasChangedSinceLastAccess(){
        return changedSinceLastAccess;
    }

    public boolean hasBecomeTrueSinceLastAccess(){
        //this collects any trues since the last access, is good for things like mouse clicks,
        //which are instantaneous and you want then recorded on the next tick
        if (valueTrueSinceLastAccess==true){
            valueTrueSinceLastAccess=false;
            return true;
        }else{
            return false;
        }
    }


    public boolean getValue(){
        changedSinceLastAccess=false;
        valueTrueSinceLastAccess=false;
        return value;
    }

    public boolean getValue_withoutNotifying(){
        return value;
    }

}