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