I’m very glad that I did it
this method is used in many games
I think it’s worth adding a similar example to the tutorial
package tests;
import com.jme3.collision.CollisionResult;
import com.jme3.collision.CollisionResults;
import com.jme3.input.ChaseCamera;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.AnalogListener;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.material.Material;
import com.jme3.math.Ray;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.shape.Sphere;
import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
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.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Spatial;
/**
* This is the Main Class of your Game. It should boot up your game and do initial initialisation
* Move your Logic into AppStates or Controls or other java classes
*/
public class Tests extends SimpleApplication {
private Spatial player;
private Node shootables;
private Geometry mark;
CharacterControl characterControl;
public static void main(String[] args) {
Tests app = new Tests();
app.setShowSettings(false); //Settings dialog not supported on mac
app.start();
}
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);
}
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");
}
final private ActionListener actionListener = new ActionListener() {
@Override
public void onAction(String name, boolean keyPressed, float tpf) {
if (name.equals("Shoot") && !keyPressed) {
Vector3f origin = cam.getWorldCoordinates(inputManager.getCursorPosition(), 0.0f);
Vector3f direction = cam.getWorldCoordinates(inputManager.getCursorPosition(), 0.3f);
direction.subtractLocal(origin).normalizeLocal();
CollisionResults results = new CollisionResults();
Ray ray = new Ray( cam.getLocation() , direction );
shootables.collideWith( ray, results );
if( results.size() > 0 ){
CollisionResult closest = results.getClosestCollision();
// Let's interact - we mark the hit with a red dot.
Vector3f contactPoint = closest.getContactPoint();
mark.setLocalTranslation(contactPoint);
rootNode.attachChild(mark);
Vector3f correction = new Vector3f(contactPoint.x,contactPoint.y+1,contactPoint.z);
moveTo = correction;
}
}
}
};
@Override
public void simpleInitApp() {
shootables = new Node("Shootables");
rootNode.attachChild(shootables);
setUpLight();
initKeys();
initMark();
//init physics
BulletAppState bulletAppState = new BulletAppState();
stateManager.attach(bulletAppState);
//ini player
player = (Spatial) assetManager.loadModel("Models/char.glb");
rootNode.attachChild(player);
//init player physics
SphereCollisionShape sphereShape = new SphereCollisionShape(1.2f);
characterControl = new CharacterControl( sphereShape , 1.2f );
characterControl.setApplyPhysicsLocal(true);
player.addControl(characterControl);
characterControl.setPhysicsLocation(new Vector3f(0,2f,0));
rootNode.attachChild(player);
//init flor
Spatial flor = assetManager.loadModel("Models/flor.glb");
shootables.attachChild(flor);
//init flor physics
CollisionShape sceneShape = CollisionShapeFactory.createMeshShape(flor);
RigidBodyControl landscape = new RigidBodyControl(sceneShape, 0);
flor.addControl(landscape);
bulletAppState.getPhysicsSpace().add(landscape);
// Disable the default first-person cam!
flyCam.setEnabled(false);
// Enable a chase cam
ChaseCamera chaseCam = new ChaseCamera(cam, player, inputManager);
//Uncomment this to invert the camera's vertical rotation Axis
//chaseCam.setInvertVerticalAxis(true);
//Uncomment this to invert the camera's horizontal rotation Axis
//chaseCam.setInvertHorizontalAxis(true);
//Comment this to disable smooth camera motion
chaseCam.setSmoothMotion(true);
}
private void setUpLight() {
// 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 Vector3f moveTo = null;
private float interp = 0.0f;
private float moveSpeed = 0.05f;
@Override
public void simpleUpdate(float tpf) {
if(moveTo != null){
//set loock at mark
characterControl.setViewDirection(mark.getLocalTranslation());
//get player position
Vector3f playerPosition = characterControl.getPhysicsLocation();
float distance = playerPosition.distance(moveTo);
if(distance > 2f){
//move character
interp += (moveSpeed/distance) * tpf;
characterControl.setPhysicsLocation(new Vector3f().interpolateLocal(playerPosition, moveTo, interp));
}else{
interp = 0.0f;
}
}
}
}