Hello picking on android

my desktop application

after 3 shoots npc die

i build apk file for andoid
and in phone
only works from a short distance

CollisionResults results = new CollisionResults();
                Ray ray = new Ray(cam.getLocation(), cam.getDirection());

                shootables.collideWith(ray, results);
                if (results.size() > 0){
                    Vector3f pt = results.getCollision(0).getContactPoint();
                    Spatial npcSpatial = (Spatial)results.getCollision(0).getGeometry().getParent().getParent().getParent();


                    EnemyControl npcControl = npcSpatial.getControl(EnemyControl.class);
                    if(npcControl != null){
                        npcControl.shuted();
                    }
                }

apk file

It looks like this lines is incorrect and could be causing your issues:

Ray collisions require a normalized unit vector for the Ray’s direction. So you need to normalize the value you get from cam.getDirection first which you can easily do with the normalize() method on any vector:

Ray ray = new Ray(cam.getLocation(), cam.getDirection().normalize());

1 Like

in desktop app works on android no

try this

                Ray ray = new Ray(cam.getLocation().normalize(), cam.getDirection().normalize());
                ray.setLimit(100f);

not work

You would not want to normalize the ray origin in this situation, because it is a locational vector. You only ever want to normalize directional vectors, like in the case of the ray’s direction.

Normalizing a vector will return a vector with the same direction but with a length of 1. For example, a vector like (0, 60, 0) will be (0, 1, 0) when it is normalized. So if you normalize a location vector, it changes the location entirely, and you never want to do that.

1 Like

thanks understand
what about problem?

cam.getDirection() should already be normalized… otherwise it wouldn’t be a direction vector and the method is incorrectly named.

You shouldn’t ever have to normalize cam.getDirection(). OP’s problem is likely elsewhere.

I think you are unlikely to get an answer for your problem report. It lacks any relevant information to solve the issue since picking on Android seems to work for “everyone else”. So it is likely a problem with your application… which means we are still in the “trouble shooting” phase.

Put together a single-class test case that illustrates the issue and I suspect you will get better answers.

Also we know you already had problems with picking on desktop and somehow solved it… but we don’t know exactly how you solved it. Maybe it is relevant.

Without code, we’re back to guessing lengths of string again.

Some trouble shooting tips;

Run with debug mode.

OR

Do print outs:

if(nextShoot< Instant.now().getEpochSecond()){
// here
            if(cartridges > 0){
// here
                cartridges = cartridges - 3;
                shootSound.play();
                CollisionResults results = new CollisionResults();
                Ray ray = new Ray(cam.getLocation(), cam.getDirection());
                shootables.collideWith(ray, results);
                if (results.size() > 0){
// here

And see if they are reached.

i create new project and add this code

package hellopickingtest.game;

import com.jme3.app.SimpleApplication;
import com.jme3.app.state.AppState;
import com.jme3.collision.CollisionResult;
import com.jme3.collision.CollisionResults;
import com.jme3.font.BitmapText;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Ray;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Sphere;

/**
 * The JMonkeyEngine game entry, you should only do initializations for your game here, game logic is handled by
 * Custom states {@link com.jme3.app.state.BaseAppState}, Custom controls {@link com.jme3.scene.control.AbstractControl}
 * and your custom entities implementations of the previous.
 *
 */
public class HelloPickingTest extends SimpleApplication {
 private Node shootables;
  private Geometry mark;
  
    public HelloPickingTest() {
    }

    public HelloPickingTest(AppState... initialStates) {
        super(initialStates);
    }

    @Override
    public void simpleInitApp() {
        initCrossHairs(); // a "+" in the middle of the screen to help aiming
    initKeys();       // load custom key mappings
    initMark();       // a red sphere to mark the hit
    /** create four colored boxes and a floor to shoot at: */
    shootables = new Node("Shootables");
    rootNode.attachChild(shootables);
    Spatial model = assetManager.loadModel("Models/test.glb");
    model.setLocalTranslation(40, 0, 40);
    shootables.attachChild(model);
    
    AmbientLight al = new AmbientLight();
        al.setColor(ColorRGBA.White.mult(1.3f));
        rootNode.addLight(al);

        DirectionalLight dl = new DirectionalLight();
        dl.setColor(ColorRGBA.White);
        dl.setDirection(new Vector3f(2.8f, -2.8f, -2.8f).normalizeLocal());
        rootNode.addLight(dl);
    }

    /** Declaring the "Shoot" action and mapping to its triggers. */
  private void initKeys() {
    inputManager.addMapping("Shoot",
      new KeyTrigger(KeyInput.KEY_SPACE), // trigger 1: spacebar
      new MouseButtonTrigger(MouseInput.BUTTON_LEFT)); // trigger 2: left-button click
    inputManager.addListener(actionListener, "Shoot");
  }
  /** Defining the "Shoot" action: Determine what was hit and how to respond. */
  final private ActionListener actionListener = new ActionListener() {
    @Override
    public void onAction(String name, boolean keyPressed, float tpf) {
      if (name.equals("Shoot") && !keyPressed) {
        // 1. Reset results list.
        CollisionResults results = new CollisionResults();
        // 2. Aim the ray from cam loc to cam direction.
        Ray ray = new Ray(cam.getLocation(), cam.getDirection());
        // 3. Collect intersections between Ray and Shootables in results list.
        shootables.collideWith(ray, results);
        // 4. Print the results
        System.out.println("----- Collisions? " + results.size() + "-----");
        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.");
        }
        // 5. Use the results (we mark the hit object)
        if (results.size() > 0) {
          // The closest collision point is what was truly hit:
          CollisionResult closest = results.getClosestCollision();
          // Let's interact - we mark the hit with a red dot.
          mark.setLocalTranslation(closest.getContactPoint());
          rootNode.attachChild(mark);
        } else {
          // No hits? Then remove the red mark.
          rootNode.detachChild(mark);
        }
      }
    }
  };


  /** A red ball that marks the last spot that was "hit" by the "shot". */
  private void initMark() {
    Sphere sphere = new Sphere(30, 30, 0.2f);
    mark = new Geometry("BOOM!", sphere);
    Material mark_mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
    mark_mat.setColor("Color", ColorRGBA.Red);
    mark.setMaterial(mark_mat);
  }

  /** A centred plus sign to help the player aim. */
  private void initCrossHairs() {
    setDisplayStatView(false);
    guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
    BitmapText ch = new BitmapText(guiFont);
    ch.setSize(guiFont.getCharSet().getRenderedSize() * 2);
    ch.setText("+"); // crosshairs
    ch.setLocalTranslation( // center
    settings.getWidth() / 2 - ch.getLineWidth()/2, settings.getHeight() / 2 + ch.getLineHeight()/2, 0);
    guiNode.attachChild(ch);
  }


}

it works.
problem in my code or in project settings

i delete physics and controlls and shoot logic

package myGame;

import com.jme3.app.SimpleApplication;
import com.jme3.audio.AudioNode;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
import com.jme3.bullet.collision.shapes.CollisionShape;
import com.jme3.bullet.collision.shapes.SphereCollisionShape;
import com.jme3.bullet.control.CharacterControl;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.bullet.util.CollisionShapeFactory;
import com.jme3.collision.CollisionResult;
import com.jme3.collision.CollisionResults;
import com.jme3.font.BitmapFont;
import com.jme3.font.BitmapText;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.light.PointLight;
import com.jme3.light.SpotLight;
import com.jme3.material.Material;
import com.jme3.material.RenderState;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Ray;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.Node;
import com.jme3.scene.SceneGraphVisitor;
import com.jme3.scene.Spatial;
import com.jme3.scene.VertexBuffer;
import com.jme3.scene.control.LightControl;
import com.jme3.scene.control.LodControl;
import com.jme3.scene.shape.Sphere;
import com.jme3.texture.Texture;
import com.jme3.ui.Picture;
import com.jme3.util.BufferUtils;
import java.time.Instant;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import jme3tools.optimize.LodGenerator;

/**
 * The JMonkeyEngine game entry, you should only do initializations for your game here, game logic is handled by
 * Custom states {@link com.jme3.app.state.BaseAppState}, Custom controls {@link com.jme3.scene.control.AbstractControl}
 * and your custom entities implementations of the previous.
 *
 * @author pavl_g.
 */
public class Game extends SimpleApplication implements ActionListener{
    public CharacterControl player;
    
    final private Vector3f walkDirection = new Vector3f();
    public static boolean left = false, right = false, up = false, down = false;
    public Node shootables;
    public Node helpers;

    //Temporary vectors used on each frame.
    //They here to avoid instantiating new vectors on each frame
    final private Vector3f camDir = new Vector3f();
    final private Vector3f camLeft = new Vector3f();
    public BulletAppState bulletAppState;
    public Spatial charPosition;
    public int hp = 100;
    public int cartridges = 30; 
    public boolean isShoot= false;
    
    BitmapText hpText;
    BitmapText cartText;

    AudioNode shootSound;
    AudioNode clickSound;
    AudioNode dieSound;
    AudioNode ahtSound;
    AudioNode runSound;
    AudioNode medSound;
    AudioNode ammoSound;
    public int enemyCount = 0;
    
    public void createObjects(){
        
        createNPC(84.75535f,0,145.94548f);
        /**
        createNPC(-63.514847f,0,52.897144f);
        createNPC(-263.35562f,0,23.480993f);
        createNPC(-404.11185f,0,140.66324f);
        createNPC(-570.4661f,0,137.26347f);
        createNPC(-582.6169f,0,245.23338f);
        createNPC(-479.92328f,0,377.19498f);
        createNPC(-564.6432f,0,480.94095f);
        createNPC(-560.56696f,0,617.89545f);
        createNPC(-458.1033f,0,728.34076f);
        createNPC(-333.29416f,0,667.6027f);
        createNPC(-238.8214f,0,734.1953f);
        createNPC(-116.35589f,0,656.0849f);
        createNPC(12.540116f,0,662.021f);
        createNPC(134.86247f,0,755.99634f);
        createNPC(89.961075f,0,552.2017f);
        createNPC(7.463149f,0,410.91074f);
        createNPC(-50.472076f,0,265.80423f);
        createNPC(-154.19882f,0,183.93684f);
        createNPC(-366.95428f,0,235.87689f);
        createNPC(-275.03964f,0,395.69656f);
        createNPC(-309.71994f,0,392.63138f);
        createNPC(-84.31912f,0,-49.766205f);
        createNPC(-322.4696f,0,-93.43058f);
        createNPC(-407.85645f,0,37.471973f);
        createNPC(-544.64886f,0,53.904488f);
        createNPC(-479.62924f,0,206.01845f);
        createNPC(-613.76056f,0,368.56186f);
        createNPC(-460.8853f,0,538.291f);
        createNPC(92.62878f,0,330.81006f);

        createAmmo(-234.51724f,0,62.50956f);
        createAmmo(-445.26013f,0,47.577297f);
        createAmmo(82.715546f,0,412.55246f);
        createAmmo(144.70927f,0,772.57965f);
        createAmmo(-289.43036f,0,731.215f);
        createAmmo(-602.96985f,0,381.3159f);
        createAmmo(458.27536f,0,445.0701f);
        createAmmo(-521.4545f,0,768.953f);
        createAmmo(-266.79315f,0,473.48358f);
        createAmmo(-463.50266f,0,267.60895f);
        createAmmo(-459.42194f,0, 576.27295f);
        createAmmo(-635.51526f,0, 75.56707f);

        createMed(175.72423f,0,817.0959f);
        createMed(-547.1941f,0,725.74634f);
        createMed(-632.7831f,0,185.85773f);
        createMed(-625.71344f,0,511.95154f);
        createMed(-458.0505f,0,333.36386f);
        createMed(-221.79033f,0,512.3054f);
        createMed(-245.66016f,0,772.30237f);
        **/
    }
    
    public void createSound(){
        ammoSound = new AudioNode(assetManager, "assets/Audio/ammo.wav",true);
        ammoSound.setLooping(false); // activate continuous playing
        ammoSound.setPositional(false);
        rootNode.attachChild(ammoSound);
        
        medSound = new AudioNode(assetManager, "assets/Audio/med.wav",true);
        medSound.setLooping(false); // activate continuous playing
        medSound.setPositional(false);
        rootNode.attachChild(medSound);
        
        runSound = new AudioNode(assetManager, "assets/Audio/run.wav",true);
        runSound.setLooping(false); // activate continuous playing
        runSound.setPositional(false);
        rootNode.attachChild(runSound);
        
        ahtSound = new AudioNode(assetManager, "assets/Audio/aht.wav",true);
        ahtSound.setLooping(false); // activate continuous playing
        ahtSound.setPositional(false);
        rootNode.attachChild(ahtSound);
        
        dieSound = new AudioNode(assetManager, "assets/Audio/die.wav",true);
        dieSound.setLooping(false); // activate continuous playing
        dieSound.setPositional(false);
        rootNode.attachChild(dieSound);
        
        shootSound = new AudioNode(assetManager, "assets/Audio/shoot.wav",true);
        shootSound.setLooping(false); // activate continuous playing
        shootSound.setPositional(false);
        rootNode.attachChild(shootSound);
        
        clickSound = new AudioNode(assetManager, "assets/Audio/click.wav",true);
        clickSound.setLooping(false); // activate continuous playing
        clickSound.setPositional(false);
        rootNode.attachChild(clickSound);
    }
    
    @Override
    public void simpleInitApp() {
        setDisplayFps(false);

        setDisplayStatView(false);
        shootables = new Node("Shootables");
        helpers = new Node("Helpers");
        
        
        

        BitmapFont guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");

        cartText = new BitmapText(guiFont, false);

        cartText.setSize(guiFont.getCharSet().getRenderedSize());
        cartText.setColor(ColorRGBA.Brown);
        cartText.setText("Cart:" + Integer.toString(cartridges));
        cartText.setLocalTranslation(0, cartText.getHeight(), 0);
        guiNode.attachChild(cartText);
        
        hpText = new BitmapText(guiFont, false);

        hpText.setSize(guiFont.getCharSet().getRenderedSize());
        hpText.setColor(ColorRGBA.Red);
        hpText.setText("HP:" + Integer.toString(hp));
        hpText.setLocalTranslation(0, hpText.getHeight()*2, 0);
        guiNode.attachChild(hpText);
        
        
            /** Set up Physics */
        bulletAppState = new BulletAppState();
        stateManager.attach(bulletAppState);

        // We re-use the flyby camera for rotation, while positioning is handled by physics
        viewPort.setBackgroundColor(new ColorRGBA(0.7f, 0.8f, 1f, 1f));
        flyCam.setMoveSpeed(100);
        setUpKeys();
        setUpLight();
        initCrossHairs();
        initKeys();
        createSound();
        createObjects();
        initMark();

        rootNode.attachChild(shootables);
        rootNode.attachChild(helpers);

        charPosition = (Spatial)assetManager.loadModel("assets/Models/gun.glb");
        rootNode.attachChild(charPosition);
        
        Spatial sceneModel =  assetManager.loadModel("assets/Models/level.glb");
        sceneModel.setLocalScale(40f);
       

        

        rootNode.attachChild(shootables);

        CollisionShape sceneShape =
                CollisionShapeFactory.createMeshShape(sceneModel);
        RigidBodyControl landscape = new RigidBodyControl(sceneShape, 0);
        sceneModel.addControl(landscape);

        // We set up collision detection for the player by creating
        // a capsule collision shape and a CharacterControl.
        // The CharacterControl offers extra settings for
        // size, step height, jumping, falling, and gravity.
        // We also put the player in its starting position.

        CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(1.5f, 6f, 1);
        player = new CharacterControl(capsuleShape, 0.02f);
        player.setJumpSpeed(20);
        player.setFallSpeed(30);
        player.setGravity(30);
        player.setPhysicsLocation(new Vector3f(107.401024f, 4f, -44.988575f));

        // We attach the scene and the player to the rootnode and the physics space,
        // to make them appear in the game world.
        rootNode.attachChild(sceneModel);
        bulletAppState.getPhysicsSpace().add(landscape);
        bulletAppState.getPhysicsSpace().add(player);
        initMark();

    }
    
    
    private void initKeys() {
    inputManager.addMapping("Shoot",      new MouseButtonTrigger(MouseInput.BUTTON_RIGHT));         // trigger 2: left-button click
    inputManager.addMapping("Position",      new KeyTrigger(KeyInput.KEY_R));         // trigger 2: left-button click

    inputManager.addListener(actionListener, "Shoot","Position"); // ... and add.
  }
    
  final private ActionListener actionListener = new ActionListener() {
    @Override
    public void onAction(String name, boolean keyPressed, float tpf) {
      if (name.equals("Shoot") && !keyPressed) {
            shoot(); 
      }
      if (name.equals("Position") && !keyPressed) {
        System.out.println("physics: " +player.getPhysicsLocation().x + " " + player.getPhysicsLocation().y +" " + player.getPhysicsLocation().z);

      }

    
    }
  };
  
  public long nextShoot = 0;
  private Geometry mark;
   private void initMark() {
    Sphere sphere = new Sphere(30, 30, 0.2f);
    mark = new Geometry("BOOM!", sphere);
    Material mark_mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
    mark_mat.setColor("Color", ColorRGBA.Red);
    mark.setMaterial(mark_mat);
  }
   
  public void shoot(){
        CollisionResults results = new CollisionResults();
        Ray ray = new Ray(cam.getLocation(), cam.getDirection());
        shootables.collideWith(ray, results);
        if (results.size() > 0){
            CollisionResult closest = results.getClosestCollision();
            mark.setLocalTranslation(closest.getContactPoint());
            rootNode.attachChild(mark);
        }
  }
   
  /**
  
  public void shoot(){
        if(nextShoot< Instant.now().getEpochSecond()){
            if(cartridges > 0){
                 cartridges = cartridges - 3;
                shootSound.play();
                CollisionResults results = new CollisionResults();
                Ray ray = new Ray(cam.getLocation(), cam.getDirection());
                shootables.collideWith(ray, results);
                if (results.size() > 0){
                    CollisionResult closest = results.getClosestCollision();
                    mark.setLocalTranslation(closest.getContactPoint());
                    rootNode.attachChild(mark);
                    
                    
                    Vector3f pt = results.getCollision(0).getContactPoint();
                    Spatial npcSpatial = (Spatial)results.getCollision(0).getGeometry().getParent().getParent().getParent();
                    
                    
                    EnemyControl npcControl = npcSpatial.getControl(EnemyControl.class);
                    if(npcControl != null){
                        npcControl.shuted();
                    }
                    
                }
             //   nextShoot = Instant.now().getEpochSecond() + 1;
            }else{
                clickSound.play();
           }
        }
  }
  **/
    
    private void initCrossHairs() {
        setDisplayStatView(false);
        guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
        BitmapText ch = new BitmapText(guiFont);
        ch.setSize(guiFont.getCharSet().getRenderedSize() * 2);
        ch.setText("+"); // crosshairs
        ch.setLocalTranslation( // center
        settings.getWidth() / 2 - ch.getLineWidth()/2, settings.getHeight() / 2 + ch.getLineHeight()/2, 0);
        guiNode.attachChild(ch);
    }
    
    SpotLight spot;
    private void setUpLight() {
        spot = new SpotLight();
        spot.setSpotRange(2000f);                           // distance
        spot.setSpotInnerAngle(15f * FastMath.DEG_TO_RAD); // inner light cone (central beam)
        spot.setSpotOuterAngle(35f * FastMath.DEG_TO_RAD); // outer light cone (edge of the light)
        spot.setColor(ColorRGBA.White.mult(1.3f));         // light color
        spot.setPosition(cam.getLocation());               // shine from camera loc
        spot.setDirection(cam.getDirection());             // shine forward from camera loc
        rootNode.addLight(spot);
        
        // We add light so we see the scene
        AmbientLight al = new AmbientLight();
        al.setColor(ColorRGBA.White.mult(1.3f));
        rootNode.addLight(al);

        DirectionalLight dl = new DirectionalLight();
        dl.setColor(ColorRGBA.White);
        dl.setDirection(new Vector3f(2.8f, -2.8f, -2.8f).normalizeLocal());
        rootNode.addLight(dl);
        
        DirectionalLight dl2 = new DirectionalLight();
        dl2.setColor(ColorRGBA.White);
       dl2.setDirection(new Vector3f(100,3,26).normalizeLocal());
       rootNode.addLight(dl2);
       
       
    }
    public void setUp(boolean value){
        up = value;
    }
    
    private void createNPC(float x,float y,float z) {
        enemyCount = enemyCount + 1;
        
        Spatial model = assetManager.loadModel("assets/Models/test.glb");
        String id = getRandomString(); 
        model.setName( id);

        
        
        
       // SphereCollisionShape sphereShape = new SphereCollisionShape(2.0f);
      //  CharacterControl myThing_phys = new CharacterControl( sphereShape , 1.2f );
      //  model.addControl(myThing_phys);
        
        
      //  bulletAppState.getPhysicsSpace().add(model);
      //  model.addControl(new EnemyControl(this)); 
      //  myThing_phys.setPhysicsLocation(new Vector3f(x,y,z));

        model.scale(1.2f);
        shootables.attachChild(model);
        /**
        Node npcNode = (Node)shootables.getChild(id);
        
        Geometry npcGeometry = (Geometry)npcNode.getChild("Object_0_0");
        LodGenerator lod = new LodGenerator(npcGeometry);
        lod.bakeLods(LodGenerator.TriangleReductionMethod.PROPORTIONAL,0.25f, 0.5f, 0.75f);
        LodControl lc = new LodControl();
        npcGeometry.addControl(lc);
        * */
    }
    
    private String getRandomString(){
        
        return Double.toString((float) Math.random());
    }
    
    private void setUpKeys() {
        inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_A));
        inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_D));
        inputManager.addMapping("Up", new KeyTrigger(KeyInput.KEY_W));
        inputManager.addMapping("Down", new KeyTrigger(KeyInput.KEY_S));
        inputManager.addMapping("Jump", new KeyTrigger(KeyInput.KEY_SPACE));

        inputManager.addListener(this, "Left");
        inputManager.addListener(this, "Right");
        inputManager.addListener(this, "Up");
        inputManager.addListener(this, "Down");
        inputManager.addListener(this, "Jump");
  }
    
    @Override
  public void onAction(String binding, boolean value, float tpf) {

    if (binding.equals("Left")) {
      if (value) { left = true; } else { left = false; }
    } else if (binding.equals("Right")) {
      if (value) { right = true; } else { right = false; }
    } else if (binding.equals("Up")) {
      if (value) { up = true; } else { up = false; }
    } else if (binding.equals("Down")) {
      if (value) { down = true; } else { down = false; }
    } else if (binding.equals("Jump")) {
      player.jump();
    }
  }
  
  public boolean isRun = false;
  public boolean isWin = false;
  @Override
  public void simpleUpdate(float tpf) {
      //win check
      if(enemyCount == 0 && isWin == false){
          isWin = true;
          Picture pic = new Picture("HUD Picture");
          pic.setImage(assetManager, "assets/Textures/win.jpg", true);
          pic.setWidth(settings.getWidth()/2);
          pic.setHeight(settings.getHeight()/2);
          pic.setPosition(settings.getWidth()/4, settings.getHeight()/4);
          guiNode.attachChild(pic);
      }
      //die check
      if(hp <0){
          dieSound.play();
          hp = 100;
          shootables.detachAllChildren();
          helpers.detachAllChildren();
          createObjects();
          player.setPhysicsLocation(new Vector3f(107.401024f, 4f, -44.988575f));

      }
     spot.setPosition(cam.getLocation());               // shine from camera loc
     spot.setDirection(cam.getDirection());   
     //is shoot andoid
     if(isShoot){
         shoot();
     }
    if(up && isRun == false){
        runSound.play();
        isRun = true;
    }else if(!up && isRun){
        runSound.stop();
        isRun = false;
    }
      
    //hp cat text updates 
    hpText.setText("HP:" + Integer.toString(hp));
    cartText.setText("Cart:" + Integer.toString(cartridges));

    //first face weapon
    Vector3f vectorDifference = new Vector3f(cam.getLocation().subtract(charPosition.getWorldTranslation()));
    charPosition.setLocalTranslation(vectorDifference.addLocal(charPosition.getLocalTranslation()));

    Quaternion worldDiff = new Quaternion(cam.getRotation().mult(charPosition.getWorldRotation().inverse()));
    charPosition.setLocalRotation(worldDiff.multLocal(charPosition.getLocalRotation()));

    charPosition.move(cam.getDirection().mult(3));
    charPosition.move(cam.getUp().mult(-0.8f));
    charPosition.move(cam.getLeft().mult(-1f));
    charPosition.rotate(0.3f, FastMath.PI, 0);

          
        
        
    //run with the camera   
        camDir.set(cam.getDirection()).multLocal(0.6f);
        camLeft.set(cam.getLeft()).multLocal(0.4f);
        walkDirection.set(0, 0, 0);
        if (left) {
            walkDirection.addLocal(camLeft);
        }
        if (right) {
            walkDirection.addLocal(camLeft.negate());
        }
        if (up) {
            walkDirection.addLocal(camDir);
        }
        if (down) {
            walkDirection.addLocal(camDir.negate());
        }
        player.setWalkDirection(walkDirection);
        cam.setLocation(player.getPhysicsLocation());
    }
    
    private void createMed(float x, int y, float z) {
        Spatial model = assetManager.loadModel("assets/Models/med.glb");
        model.setLocalTranslation(x, y, z);
        model.addControl(new MedControl(this));
        helpers.attachChild(model);
    }
    
    private void createAmmo(float x, int y, float z) {
        Spatial model = assetManager.loadModel("assets/Models/ammo.glb");
        model.setLocalTranslation(x, y, z);
        model.addControl(new AmmoControl(this));
        helpers.attachChild(model);
    }
    
}

work in desktop and dont wokr on android
maybe in application settings problem?

the pointer has a deviation
the farther away from the object the greater the deviation I think

        Ray ray = new Ray(cam.getLocation(), cam.getDirection());

wrong cam.getDirection()?

i create new project and paste my code,

and when i use android launcher with this code

package hellopickingtest.android;

import com.jme3.app.AndroidHarness;
import hellopickingtest.game.HelloPickingTest;


public class AndroidLauncher extends AndroidHarness {
    
    public AndroidLauncher() {
        appClass = HelloPickingTest.class.getCanonicalName();
    }
}

it work normal
when in use this code picking not work

package com.example.androidmodule;

import android.os.Bundle;
import android.os.PersistableBundle;
import android.view.View;
import android.view.MotionEvent;

import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.jme3.app.LegacyApplication;
import com.jme3.app.jmeSurfaceView.JmeSurfaceView;
import com.jme3.app.jmeSurfaceView.OnExceptionThrown;
import com.jme3.app.jmeSurfaceView.OnRendererCompleted;
import com.jme3.system.AppSettings;
import myGame.Game;
import android.widget.Button;
import android.widget.LinearLayout;
/**
 * Used to create an Android Activity, the main entry for {@link android.view.Choreographer} to render Ui-Components.
 *
 * @author pavl_g.
 */
public class AndroidLauncher extends AppCompatActivity implements OnRendererCompleted, OnExceptionThrown {
    private JmeSurfaceView jmeSurfaceView;
    private static LegacyApplication legacyApplication;
    private Game game;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        gl_startGame();
    }

    @Override
    public void onPostCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {
        super.onPostCreate(savedInstanceState, persistentState);

    }
    JmeSurfaceView gl_surfaceView;
    protected void gl_startGame(){
        gl_surfaceView = findViewById(R.id.glView);
        gl_surfaceView.setUseJoyStickEvents(false);
        game= new Game();
        //pass jme game to the GLContext
        if(legacyApplication == null) {
            game = new Game();
            legacyApplication = new Game();
            legacyApplication = game;
            gl_surfaceView.setLegacyApplication(game);
        }else{
            gl_surfaceView.setLegacyApplication(legacyApplication);
        }
        //set listeners
        gl_surfaceView.setOnRendererCompleted(this);
        gl_surfaceView.setOnExceptionThrown(this);

        gl_surfaceView.startRenderer(0);
        //LinearLayout layout = new LinearLayout(this);
        //layout.setOrientation(LinearLayout.VERTICAL);
        //test android views (native android Ui -- managed by Choreographer)
        
        Button run = (Button)findViewById(R.id.run);
        run.setText("Run");
        run.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction() == MotionEvent.ACTION_DOWN) {
                    game.up = true;
                } else if (event.getAction() == MotionEvent.ACTION_UP) {
                    game.up = false;
                }
                return true;
            }
        });
        
        Button close = (Button)findViewById(R.id.close);
        close.setText("Close");
        close.setPadding(10,10,10,10);

        close.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finishAffinity();
                System.exit(0);
            }
        });
        
        Button shoot = (Button)findViewById(R.id.shoot);
        shoot.setText("Shoot");
        shoot.setPadding(10,10,10,10);

        shoot.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction() == MotionEvent.ACTION_DOWN) {
                    game.isShoot = true;
                } else if (event.getAction() == MotionEvent.ACTION_UP) {
                    game.isShoot = false;
                }
                return true;
            }
        });
        //linearLayout.addView(run);
        //linearLayout.addView(close);

            //shallow copying the surface view to be managed by the life cycle
        this.jmeSurfaceView = gl_surfaceView;
    }

    @Override
    public void onExceptionThrown(Throwable e) {
        System.out.println(e.getMessage());
    }

    @Override
    public void onRenderCompletion(LegacyApplication application, AppSettings appSettings) {
        System.out.println("Rendering completed : " + application.getClass().getName());
    }

    /**
     * Fired when the screen has/hasNo touch/mouse focus.
     * @param hasFocus specify whether the current screen has focus or not
     */
    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        /*get the view from the current activity*/
        final View decorView = AndroidLauncher.this.getWindow().getDecorView();
        /*hide navigation bar, apply fullscreen, hide status bar, immersive sticky to disable the system bars(nav & status) from showing up when user wipes the screen*/
        decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
                View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
                View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //keep the static pointer live and destroy the old game
        jmeSurfaceView = null;
//        jmeSurfaceView.getLegacyApplication().stop(!jmeSurfaceView.isGLThreadPaused());
    }

    @Override
    protected void onPause() {
        super.onPause();
        jmeSurfaceView.loseFocus();
    }

    @Override
    protected void onResume() {
        super.onResume();
        jmeSurfaceView.gainFocus();
    }
}

It seems you are using android views to handle shooting in jMonkeyEngine, notice that android UI runs on a separate thread (the main looper thread), while jme runs on the GLES thread, so you need to synchronize callbacks from android UI and enqueue them on the jme update which will be triggered on the next update pass…

There are 3 major ways to synchronize components (variables for example) among 2 threads:

  1. Use the non-blocking volatile keyword.
  2. Use ReentrantLocks (not recommended in this case, but it will work).
  3. Use callbacks (this is the best !).

jMonkeyEngine provides callbacks out of the box, however you can still build your own customized callbacks through extending a BaseAppState.

Example for using jme3 SimpleApplication#enqueue(Runnable):

final Button shoot = findViewById(R.id.shoot);
shoot.setOnTouchListener((view, event) -> {
     final boolean[] isShoot = new boolean[] { false };
     if (event.getAction() == MotionEvent.ACTION_DOWN) {
            isShoot[0] = true;
      } else if (event.getAction() == MotionEvent.ACTION_UP) {
           isShoot[0] = false;
      }
   /* a callback to the application update */
   game.enqueue(() -> game.isShoot = isShoot[0]);
   return true;
});

Now changes from android UI will be visible to your game.

2 Likes

Try this code but picking not work correctly

Could you share what you have tried specifically ?

1 Like

minute

main class

package hellopickingtest.game;

import com.jme3.app.SimpleApplication;
import com.jme3.audio.AudioNode;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.collision.shapes.CapsuleCollisionShape;
import com.jme3.bullet.collision.shapes.CollisionShape;
import com.jme3.bullet.collision.shapes.SphereCollisionShape;
import com.jme3.bullet.control.CharacterControl;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.bullet.util.CollisionShapeFactory;
import com.jme3.collision.CollisionResult;
import com.jme3.collision.CollisionResults;
import com.jme3.font.BitmapFont;
import com.jme3.font.BitmapText;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.light.PointLight;
import com.jme3.light.SpotLight;
import com.jme3.material.Material;
import com.jme3.material.RenderState;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Ray;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.Node;
import com.jme3.scene.SceneGraphVisitor;
import com.jme3.scene.Spatial;
import com.jme3.scene.VertexBuffer;
import com.jme3.scene.control.LightControl;
import com.jme3.scene.control.LodControl;
import com.jme3.scene.shape.Sphere;
import com.jme3.texture.Texture;
import com.jme3.ui.Picture;
import com.jme3.util.BufferUtils;
import java.time.Instant;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import jme3tools.optimize.LodGenerator;

/**
 * The JMonkeyEngine game entry, you should only do initializations for your game here, game logic is handled by
 * Custom states {@link com.jme3.app.state.BaseAppState}, Custom controls {@link com.jme3.scene.control.AbstractControl}
 * and your custom entities implementations of the previous.
 *
 */
public class HelloPickingTest extends SimpleApplication implements ActionListener{
    public CharacterControl player;
    
    final private Vector3f walkDirection = new Vector3f();
    public static boolean left = false, right = false, up = false, down = false;
    public Node shootables;
    public Node helpers;

    //Temporary vectors used on each frame.
    //They here to avoid instantiating new vectors on each frame
    final private Vector3f camDir = new Vector3f();
    final private Vector3f camLeft = new Vector3f();
    public BulletAppState bulletAppState;
    public Spatial charPosition;
    public int hp = 100;
    public int cartridges = 30; 
    public boolean isShoot= false;
    
    BitmapText hpText;
    BitmapText cartText;

    AudioNode shootSound;
    AudioNode clickSound;
    AudioNode dieSound;
    AudioNode ahtSound;
    AudioNode runSound;
    AudioNode medSound;
    AudioNode ammoSound;
    public int enemyCount = 0;
    
    public void createObjects(){
        
        createNPC(107.453f,0,-152.9184f);
        /**
        createNPC(84.75535f,0,145.94548f);
        createNPC(-63.514847f,0,52.897144f);
        createNPC(-263.35562f,0,23.480993f);
        createNPC(-404.11185f,0,140.66324f);
        createNPC(-570.4661f,0,137.26347f);
        createNPC(-582.6169f,0,245.23338f);
        createNPC(-479.92328f,0,377.19498f);
        createNPC(-564.6432f,0,480.94095f);
        createNPC(-560.56696f,0,617.89545f);
        createNPC(-458.1033f,0,728.34076f);
        createNPC(-333.29416f,0,667.6027f);
        createNPC(-238.8214f,0,734.1953f);
        createNPC(-116.35589f,0,656.0849f);
        createNPC(12.540116f,0,662.021f);
        createNPC(134.86247f,0,755.99634f);
        createNPC(89.961075f,0,552.2017f);
        createNPC(7.463149f,0,410.91074f);
        createNPC(-50.472076f,0,265.80423f);
        createNPC(-154.19882f,0,183.93684f);
        createNPC(-366.95428f,0,235.87689f);
        createNPC(-275.03964f,0,395.69656f);
        createNPC(-309.71994f,0,392.63138f);
        createNPC(-84.31912f,0,-49.766205f);
        createNPC(-322.4696f,0,-93.43058f);
        createNPC(-407.85645f,0,37.471973f);
        createNPC(-544.64886f,0,53.904488f);
        createNPC(-479.62924f,0,206.01845f);
        createNPC(-613.76056f,0,368.56186f);
        createNPC(-460.8853f,0,538.291f);
        createNPC(92.62878f,0,330.81006f);

        createAmmo(-234.51724f,0,62.50956f);
        createAmmo(-445.26013f,0,47.577297f);
        createAmmo(82.715546f,0,412.55246f);
        createAmmo(144.70927f,0,772.57965f);
        createAmmo(-289.43036f,0,731.215f);
        createAmmo(-602.96985f,0,381.3159f);
        createAmmo(458.27536f,0,445.0701f);
        createAmmo(-521.4545f,0,768.953f);
        createAmmo(-266.79315f,0,473.48358f);
        createAmmo(-463.50266f,0,267.60895f);
        createAmmo(-459.42194f,0, 576.27295f);
        createAmmo(-635.51526f,0, 75.56707f);

        createMed(175.72423f,0,817.0959f);
        createMed(-547.1941f,0,725.74634f);
        createMed(-632.7831f,0,185.85773f);
        createMed(-625.71344f,0,511.95154f);
        createMed(-458.0505f,0,333.36386f);
        createMed(-221.79033f,0,512.3054f);
        createMed(-245.66016f,0,772.30237f);
        **/
    }
    
    public void createSound(){
        ammoSound = new AudioNode(assetManager, "Sounds/ammo.wav",true);
        ammoSound.setLooping(false); // activate continuous playing
        ammoSound.setPositional(false);
        rootNode.attachChild(ammoSound);
        
        medSound = new AudioNode(assetManager, "Sounds/med.wav",true);
        medSound.setLooping(false); // activate continuous playing
        medSound.setPositional(false);
        rootNode.attachChild(medSound);
        
        runSound = new AudioNode(assetManager, "Sounds/run.wav",true);
        runSound.setLooping(false); // activate continuous playing
        runSound.setPositional(false);
        rootNode.attachChild(runSound);
        
        ahtSound = new AudioNode(assetManager, "Sounds/aht.wav",true);
        ahtSound.setLooping(false); // activate continuous playing
        ahtSound.setPositional(false);
        rootNode.attachChild(ahtSound);
        
        dieSound = new AudioNode(assetManager, "Sounds/die.wav",true);
        dieSound.setLooping(false); // activate continuous playing
        dieSound.setPositional(false);
        rootNode.attachChild(dieSound);
        
        shootSound = new AudioNode(assetManager, "Sounds/shoot.wav",true);
        shootSound.setLooping(false); // activate continuous playing
        shootSound.setPositional(false);
        rootNode.attachChild(shootSound);
        
        clickSound = new AudioNode(assetManager, "Sounds/click.wav",true);
        clickSound.setLooping(false); // activate continuous playing
        clickSound.setPositional(false);
        rootNode.attachChild(clickSound);
    }
    
    @Override
    public void simpleInitApp() {
        setDisplayFps(false);

        setDisplayStatView(false);
        shootables = new Node("Shootables");
        helpers = new Node("Helpers");
        
        
        

        BitmapFont guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");

        cartText = new BitmapText(guiFont, false);

        cartText.setSize(guiFont.getCharSet().getRenderedSize() +15);
        cartText.setColor(ColorRGBA.Green);
        cartText.setText("Cart:" + Integer.toString(cartridges));
        cartText.setLocalTranslation(0, cartText.getHeight(), 0);
        guiNode.attachChild(cartText);
        
        hpText = new BitmapText(guiFont, false);

        hpText.setSize(guiFont.getCharSet().getRenderedSize() +15);
        hpText.setColor(ColorRGBA.Red);
        hpText.setText("HP:" + Integer.toString(hp));
        hpText.setLocalTranslation(0, hpText.getHeight()*2, 0);
        guiNode.attachChild(hpText);
        
        
            /** Set up Physics */
        bulletAppState = new BulletAppState();
        stateManager.attach(bulletAppState);

        // We re-use the flyby camera for rotation, while positioning is handled by physics
        viewPort.setBackgroundColor(new ColorRGBA(0.7f, 0.8f, 1f, 1f));
        flyCam.setMoveSpeed(0);
        setUpKeys();
        setUpLight();
        initCrossHairs();
        initKeys();
        createSound();
        createObjects();

        rootNode.attachChild(shootables);
        rootNode.attachChild(helpers);

        charPosition = (Spatial)assetManager.loadModel("Models/gun.glb");
        rootNode.attachChild(charPosition);
        
        Spatial sceneModel =  assetManager.loadModel("Models/level.glb");
        sceneModel.setLocalScale(40f);
       

        

        rootNode.attachChild(shootables);

        CollisionShape sceneShape =
                CollisionShapeFactory.createMeshShape(sceneModel);
        RigidBodyControl landscape = new RigidBodyControl(sceneShape, 0);
        sceneModel.addControl(landscape);

        // We set up collision detection for the player by creating
        // a capsule collision shape and a CharacterControl.
        // The CharacterControl offers extra settings for
        // size, step height, jumping, falling, and gravity.
        // We also put the player in its starting position.

        CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(1.5f, 6f, 1);
        player = new CharacterControl(capsuleShape, 0.02f);
        player.setJumpSpeed(20);
        player.setFallSpeed(30);
        player.setGravity(30);
        player.setPhysicsLocation(new Vector3f(107.401024f, 4f, -44.988575f));
        
        // We attach the scene and the player to the rootnode and the physics space,
        // to make them appear in the game world.
        rootNode.attachChild(sceneModel);
        bulletAppState.getPhysicsSpace().add(landscape);
        bulletAppState.getPhysicsSpace().add(player);

    }
    
    
    private void initKeys() {
    inputManager.addMapping("Shoot",      new MouseButtonTrigger(MouseInput.BUTTON_RIGHT));         // trigger 2: left-button click
    inputManager.addMapping("Position",      new KeyTrigger(KeyInput.KEY_R));         // trigger 2: left-button click

    inputManager.addListener(actionListener, "Run","Shoot"); // ... and add.
  }
    
  final private ActionListener actionListener = new ActionListener() {
    @Override
    public void onAction(String name, boolean keyPressed, float tpf) {
      if (name.equals("Shoot") ) {
          shoot();
      }
    }
  };
  
  public long nextShoot = 0;

   

  
  
  public void shoot(){

    CollisionResults results = new CollisionResults();
    Ray ray = new Ray(cam.getLocation(), cam.getDirection());
    shootables.collideWith(ray, results);
    if (results.size() > 0){
        if(nextShoot< Instant.now().getEpochSecond()){
            if(cartridges > 0){
                cartridges = cartridges - 3;
                shootSound.play();



                Vector3f pt = results.getCollision(0).getContactPoint();
                Spatial npcSpatial = (Spatial)results.getCollision(0).getGeometry().getParent().getParent().getParent();


                EnemyControl npcControl = npcSpatial.getControl(EnemyControl.class);
                if(npcControl != null){
                    npcControl.shuted();
                }
                    nextShoot = Instant.now().getEpochSecond() + 1;
            }else{
                clickSound.play();
            }
        }
    }

  }

    
    private void initCrossHairs() {
        setDisplayStatView(false);
        guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
        BitmapText ch = new BitmapText(guiFont);
        ch.setSize(guiFont.getCharSet().getRenderedSize() * 2);
        ch.setText("+"); // crosshairs
        ch.setLocalTranslation( // center
        settings.getWidth() / 2 - ch.getLineWidth()/2, settings.getHeight() / 2 + ch.getLineHeight()/2, 0);
        guiNode.attachChild(ch);
    }
    
    SpotLight spot;
    private void setUpLight() {
        spot = new SpotLight();
        spot.setSpotRange(2000f);                           // distance
        spot.setSpotInnerAngle(15f * FastMath.DEG_TO_RAD); // inner light cone (central beam)
        spot.setSpotOuterAngle(35f * FastMath.DEG_TO_RAD); // outer light cone (edge of the light)
        spot.setColor(ColorRGBA.White.mult(1.3f));         // light color
        spot.setPosition(cam.getLocation());               // shine from camera loc
        spot.setDirection(cam.getDirection());             // shine forward from camera loc
        rootNode.addLight(spot);
        
        // We add light so we see the scene
        AmbientLight al = new AmbientLight();
        al.setColor(ColorRGBA.White.mult(1.3f));
        rootNode.addLight(al);

        DirectionalLight dl = new DirectionalLight();
        dl.setColor(ColorRGBA.White);
        dl.setDirection(new Vector3f(2.8f, -2.8f, -2.8f).normalizeLocal());
        rootNode.addLight(dl);
        
        DirectionalLight dl2 = new DirectionalLight();
        dl2.setColor(ColorRGBA.White);
       dl2.setDirection(new Vector3f(100,3,26).normalizeLocal());
       rootNode.addLight(dl2);
       
       
    }

    
    private void createNPC(float x,float y,float z) {
        enemyCount = enemyCount + 1;
        
        Spatial model = assetManager.loadModel("Models/test.glb");
        String id = getRandomString(); 
        model.setName( id);

        
        
        
        SphereCollisionShape sphereShape = new SphereCollisionShape(2.0f);
        CharacterControl myThing_phys = new CharacterControl( sphereShape , 1.2f );
        model.addControl(myThing_phys);
        
        
        bulletAppState.getPhysicsSpace().add(model);
        model.addControl(new EnemyControl(this)); 
        myThing_phys.setPhysicsLocation(new Vector3f(x,y,z));

        model.scale(1.2f);
        shootables.attachChild(model);
        
        Node npcNode = (Node)shootables.getChild(id);
        
        Geometry npcGeometry = (Geometry)npcNode.getChild("Object_0_0");
        LodGenerator lod = new LodGenerator(npcGeometry);
        lod.bakeLods(LodGenerator.TriangleReductionMethod.PROPORTIONAL,0.25f, 0.5f, 0.75f);
        LodControl lc = new LodControl();
        npcGeometry.addControl(lc);
        
    }
    
    private String getRandomString(){
        
        return Double.toString((float) Math.random());
    }
    
    private void setUpKeys() {
        inputManager.addMapping("Left", new KeyTrigger(KeyInput.KEY_A));
        inputManager.addMapping("Right", new KeyTrigger(KeyInput.KEY_D));
        inputManager.addMapping("Up", new KeyTrigger(KeyInput.KEY_W));
        inputManager.addMapping("Down", new KeyTrigger(KeyInput.KEY_S));
        inputManager.addMapping("Jump", new KeyTrigger(KeyInput.KEY_SPACE));

        inputManager.addListener(this, "Left");
        inputManager.addListener(this, "Right");
        inputManager.addListener(this, "Up");
        inputManager.addListener(this, "Down");
        inputManager.addListener(this, "Jump");
  }
    
    @Override
  public void onAction(String binding, boolean value, float tpf) {

    if (binding.equals("Left")) {
      if (value) { left = true; } else { left = false; }
    } else if (binding.equals("Right")) {
      if (value) { right = true; } else { right = false; }
    } else if (binding.equals("Up")) {
      if (value) { up = true; } else { up = false; }
    } else if (binding.equals("Down")) {
      if (value) { down = true; } else { down = false; }
    } else if (binding.equals("Jump")) {
      player.jump();
    }
  }
  
  public boolean isRun = false;
  public boolean isWin = false;
  @Override
  public void simpleUpdate(float tpf) {
      //System.out.println(player.getPhysicsLocation().x +" "+player.getPhysicsLocation().y + " " + player.getPhysicsLocation().z);
     if(isShoot){
         shoot();
     }
      if(enemyCount == 0 && isWin == false){
          isWin = true;
          Picture pic = new Picture("HUD Picture");
          pic.setImage(assetManager, "Textures/win.jpg", true);
          pic.setWidth(settings.getWidth()/2);
          pic.setHeight(settings.getHeight()/2);
          pic.setPosition(settings.getWidth()/4, settings.getHeight()/4);
          guiNode.attachChild(pic);
      }
      //die check
      if(hp <0){
          dieSound.play();
          hp = 100;
          shootables.detachAllChildren();
          helpers.detachAllChildren();
          createObjects();
          player.setPhysicsLocation(new Vector3f(107.401024f, 4f, -44.988575f));

      }
     spot.setPosition(cam.getLocation());               // shine from camera loc
     spot.setDirection(cam.getDirection());   
     //is shoot andoid

    if(up && isRun == false){
        runSound.play();
        isRun = true;
    }else if(!up && isRun){
        runSound.stop();
        isRun = false;
    }
      
    //hp cat text updates 
    hpText.setText("HP:" + Integer.toString(hp));
    cartText.setText("Cart:" + Integer.toString(cartridges));
    
    
    //first face weapon
    Vector3f vectorDifference = new Vector3f(cam.getLocation().subtract(charPosition.getWorldTranslation()));
    charPosition.setLocalTranslation(vectorDifference.addLocal(charPosition.getLocalTranslation()));

    Quaternion worldDiff = new Quaternion(cam.getRotation().mult(charPosition.getWorldRotation().inverse()));
    charPosition.setLocalRotation(worldDiff.multLocal(charPosition.getLocalRotation()));

    charPosition.move(cam.getDirection().mult(3));
    charPosition.move(cam.getUp().mult(-0.8f));
    charPosition.move(cam.getLeft().mult(-1f));
    charPosition.rotate(0.3f, FastMath.PI, 0);
    
          
        
        
    //run with the camera   
    
        camDir.set(cam.getDirection()).multLocal(0.6f);
        camLeft.set(cam.getLeft()).multLocal(0.4f);
        walkDirection.set(0, 0, 0);
        if (left) {
            walkDirection.addLocal(camLeft);
        }
        if (right) {
            walkDirection.addLocal(camLeft.negate());
        }
        if (up) {
            walkDirection.addLocal(camDir);
        }
        if (down) {
            walkDirection.addLocal(camDir.negate());
        }
        player.setWalkDirection(walkDirection.mult(0.4f));
        cam.setLocation(player.getPhysicsLocation());
        
    }
    
    private void createMed(float x, int y, float z) {
        Spatial model = assetManager.loadModel("Models/med.glb");
        model.setLocalTranslation(x, y, z);
        model.addControl(new MedControl(this));
        helpers.attachChild(model);
    }
    
    private void createAmmo(float x, int y, float z) {
        Spatial model = assetManager.loadModel("Models/ammo.glb");
        model.setLocalTranslation(x, y, z);
        model.addControl(new AmmoControl(this));
        helpers.attachChild(model);
    }
    
}

android launcher

package hellopickingtest.android;

import android.os.Bundle;
import android.os.PersistableBundle;
import android.view.View;
import android.view.MotionEvent;

import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.jme3.app.LegacyApplication;
import com.jme3.app.jmeSurfaceView.JmeSurfaceView;
import com.jme3.app.jmeSurfaceView.OnExceptionThrown;
import com.jme3.app.jmeSurfaceView.OnRendererCompleted;
import com.jme3.system.AppSettings;
import hellopickingtest.game.HelloPickingTest;
import android.widget.Button;
import android.widget.LinearLayout;
/**
 * Used to create an Android Activity, the main entry for {@link android.view.Choreographer} to render Ui-Components.
 *
 * @author pavl_g.
 */
public class AndroidLauncher extends AppCompatActivity implements OnRendererCompleted, OnExceptionThrown {
    private JmeSurfaceView jmeSurfaceView;
    private static LegacyApplication legacyApplication;
    private HelloPickingTest game;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        gl_startGame();
    }

    @Override
    public void onPostCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {
        super.onPostCreate(savedInstanceState, persistentState);

    }
    JmeSurfaceView gl_surfaceView;
    protected void gl_startGame(){
        gl_surfaceView = findViewById(R.id.glView);
        gl_surfaceView.setUseJoyStickEvents(false);
        game= new HelloPickingTest();
        //pass jme game to the GLContext
        if(legacyApplication == null) {
            game = new HelloPickingTest();
            legacyApplication = new HelloPickingTest();
            legacyApplication = game;
            gl_surfaceView.setLegacyApplication(game);
        }else{
            gl_surfaceView.setLegacyApplication(legacyApplication);
        }
        //set listeners
        gl_surfaceView.setOnRendererCompleted(this);
        gl_surfaceView.setOnExceptionThrown(this);

        gl_surfaceView.startRenderer(0);
        //LinearLayout layout = new LinearLayout(this);
        //layout.setOrientation(LinearLayout.VERTICAL);
        //test android views (native android Ui -- managed by Choreographer)
        
        Button run = (Button)findViewById(R.id.run);
        run.setText("Run");
        run.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction() == MotionEvent.ACTION_DOWN) {
                    game.up = true;
                } else if (event.getAction() == MotionEvent.ACTION_UP) {
                    game.up = false;
                }
                return true;
            }
        });
        
        Button close = (Button)findViewById(R.id.close);
        close.setText("Close");
        close.setPadding(10,10,10,10);
        
        close.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finishAffinity();
                System.exit(0);
            }
        });
        
        final Button shoot = findViewById(R.id.shoot);
        shoot.setText("Shoot");

        shoot.setOnTouchListener((view, event) -> {
             final boolean[] isShoot = new boolean[] { false };
             if (event.getAction() == MotionEvent.ACTION_DOWN) {
                    isShoot[0] = true;
              } else if (event.getAction() == MotionEvent.ACTION_UP) {
                   isShoot[0] = false;
              }
           /* a callback to the application update */
           game.enqueue(() -> game.isShoot = isShoot[0]);
           return true;
        });
        //linearLayout.addView(run);
        //linearLayout.addView(close);

            //shallow copying the surface view to be managed by the life cycle
        this.jmeSurfaceView = gl_surfaceView;
    }

    @Override
    public void onExceptionThrown(Throwable e) {
        System.out.println(e.getMessage());
    }

    @Override
    public void onRenderCompletion(LegacyApplication application, AppSettings appSettings) {
        System.out.println("Rendering completed : " + application.getClass().getName());
    }

    /**
     * Fired when the screen has/hasNo touch/mouse focus.
     * @param hasFocus specify whether the current screen has focus or not
     */
    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        /*get the view from the current activity*/
        final View decorView = AndroidLauncher.this.getWindow().getDecorView();
        /*hide navigation bar, apply fullscreen, hide status bar, immersive sticky to disable the system bars(nav & status) from showing up when user wipes the screen*/
        decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
                View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
                View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //keep the static pointer live and destroy the old game
        jmeSurfaceView = null;
//        jmeSurfaceView.getLegacyApplication().stop(!jmeSurfaceView.isGLThreadPaused());
    }

    @Override
    protected void onPause() {
        super.onPause();
        jmeSurfaceView.loseFocus();
    }

    @Override
    protected void onResume() {
        super.onResume();
        jmeSurfaceView.gainFocus();
    }
}

project

1 Like