Мое чтение этого вопроса состоит в том, что цель состоит в том, чтобы не стрелять, когда камера смотрит, но когда курсор (не в центре экрана).
Это может быть достигнуто с помощью команды cam.getWorldCoordinates(screenPosition, zDepth);
, это возвращает трехмерную точку в пространстве, которая попадет на экран точки на экране. Поэтому, если мы создадим точку в zDepth из нуля и точку в zDepth одного из них, мы можем создать луч, исходящий из положения курсора, перемещающегося наружу, чтобы было выбрано что-либо, что курсор «перевернут». 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;
}
}
вау Thats здорово! –