Hi,
I’m currently new with Jme3. Before build a complete game, I want to test many features.
I successed show a terrain, add physics and move a character on it with keyboard.
Now I want to move the caracter by clicking on target location.
I read that topic : AI plugin now with NavMesh pathfinding
I tried to do this but unsuccessfull.
I think my problem is located on NavMesh generation.
I use : __jmonkeyengine.googlecode.com/svn/trunk/sdk/jme3-navmesh-gen/src/com/jme3/gde/nmgen/NavMeshGenerator.java
And my terrain is mountains512.png.
I althrought use this piece of code :
public Geometry createNavMesh(Node node) {
Mesh mesh = new Mesh();
NavMesh navMesh = new NavMesh();
NavMeshGenerator generator = new NavMeshGenerator();
generator.setCellHeight(1f);
GeometryBatchFactory.mergeGeometries(findGeometries(node, new LinkedList<Geometry>()), mesh);
Mesh optiMesh = generator.optimize(mesh);
navMesh.loadFromMesh(optiMesh);
Geometry navGeom = new Geometry("NavMesh");
navGeom.setMesh(optiMesh);
Material green = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
green.setColor("Color", ColorRGBA.Green);
green.getAdditionalRenderState().setWireframe(true);
navGeom.setMaterial(green);
return navGeom;
}
Here is the result :
SCREENSHOT
I think there isn’t enough triangles no ?
Thanks for help, and sorry for my english
Edit : here is my entire code
MyGame.java
package fr.flow10000.akkad;
import com.jme3.ai.navmesh.NavMesh;
import com.jme3.ai.navmesh.NavMeshPathfinder;
import com.jme3.ai.navmesh.Path.Waypoint;
import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.control.BetterCharacterControl;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.collision.CollisionResult;
import com.jme3.collision.CollisionResults;
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.material.Material;
import com.jme3.math.ColorRGBA;
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.Node;
import com.jme3.scene.Spatial;
import com.jme3.terrain.geomipmap.TerrainQuad;
import com.jme3.terrain.heightmap.AbstractHeightMap;
import com.jme3.terrain.heightmap.ImageBasedHeightMap;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture.WrapMode;
import fr.flow10000.akkad.camera.MyCamera;
import fr.flow10000.akkad.utils.NavMeshUtils;
public class MyGame extends SimpleApplication implements ActionListener {
private static final float FORWARD_SPEED = 10;
private static final float BACKWARD_SPEED = 4;
private static final float ROTATE_SPEED = .0006f;
private MyCamera myCamera;
private TerrainQuad terrain;
private NavMesh navMesh;
private Spatial player;
private BetterCharacterControl playerControl;
private Node playerNode;
private Node terrainNode;
private BulletAppState bulletAppState;
private NavMeshPathfinder pathfinder = null;
private Vector3f walkDirection = new Vector3f(0, 0, 0);
private Vector3f viewDirection = new Vector3f(0, 0, 1);
private boolean rotateLeft = false, rotateRight = false, forward = false, backward = false, walk = false;
@Override
public void simpleInitApp() {
Material genericSpacialMaterial = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
genericSpacialMaterial.setColor("Color", ColorRGBA.Blue);
Material materialPlayer = new Material(assetManager, "Common/MatDefs/Misc/ShowNormals.j3md");
player = assetManager.loadModel("player.j3o");
player.setMaterial(materialPlayer);
playerNode = new Node();
playerNode.attachChild(player);
terrainNode = new Node();
initTerrain(); // load terrain (mountains512)
initNav(); // build navmesh
rootNode.attachChild(playerNode);
rootNode.attachChild(terrainNode);
initPhysics();
initKeys();
initCamera();
// bulletAppState.getPhysicsSpace().enableDebug(assetManager);
}
public void onAction(String name, boolean isPressed, float tpf) {
if (name.equals("Rotate Left")) {
rotateLeft = isPressed;
walk = false;
} else if (name.equals("Rotate Right")) {
rotateRight = isPressed;
walk = false;
} else if (name.equals("Forward")) {
forward = isPressed;
walk = false;
} else if (name.equals("Back")) {
backward = isPressed;
walk = false;
} else if (name.equals("Generic Mouse Action") && isPressed) {
this.onGenericMouseAction();
}
}
private void onGenericMouseAction() {
CollisionResults results = new CollisionResults();
Vector2f click2d = inputManager.getCursorPosition();
Vector3f click3d = cam.getWorldCoordinates(new Vector2f(click2d.x, click2d.y), 0f).clone();
Vector3f dir = cam.getWorldCoordinates(new Vector2f(click2d.x, click2d.y), 1f).subtractLocal(click3d).normalizeLocal();
Ray ray = new Ray(click3d, dir);
rootNode.collideWith(ray, results);
if (results.size() > 0) {
CollisionResult result = results.getClosestCollision();
Geometry target = result.getGeometry();
if (target.getName().startsWith("TERRAIN")) {
Vector3f startPoint = new Vector3f(player.getWorldTranslation());
Vector3f targetPoint = new Vector3f(result.getContactPoint());
pathfinder = new NavMeshPathfinder(navMesh);
pathfinder.setPosition(startPoint);
pathfinder.computePath(targetPoint);
walk = true;
}
} else {
System.out.println(">>> NOTHING");
}
}
@Override
public void simpleUpdate(float tpf) {
if (walk) {
Waypoint waypoint = pathfinder.getNextWaypoint();
if (waypoint == null) {
walk = false;
return;
}
Vector3f vector = waypoint.getPosition().subtract(player.getWorldTranslation());
if (!(vector.length() < 1)) {
player.move(vector.normalize().multLocal(FORWARD_SPEED * tpf));
} else if (!pathfinder.isAtGoalWaypoint()) {
pathfinder.goToNextWaypoint();
} else {
walk = false;
}
return;
}
Vector3f modelForwardDir = cam.getDirection();
walkDirection.set(0, 0, 0);
if (forward) {
walkDirection.addLocal(modelForwardDir.mult(FORWARD_SPEED));
} else if (backward) {
walkDirection.addLocal(modelForwardDir.mult(BACKWARD_SPEED).negate());
}
playerControl.setWalkDirection(walkDirection);
if (rotateLeft) {
Quaternion rotateL = new Quaternion().fromAngleAxis(ROTATE_SPEED, Vector3f.UNIT_Y);
rotateL.multLocal(viewDirection);
myCamera.onRotatePlayer(-ROTATE_SPEED);
} else if (rotateRight) {
Quaternion rotateR = new Quaternion().fromAngleAxis(-ROTATE_SPEED, Vector3f.UNIT_Y);
rotateR.multLocal(viewDirection);
myCamera.onRotatePlayer(ROTATE_SPEED);
}
playerControl.setViewDirection(viewDirection);
}
private void initKeys() {
inputManager.addMapping("Forward", new KeyTrigger(KeyInput.KEY_Z));
inputManager.addMapping("Back", new KeyTrigger(KeyInput.KEY_S));
inputManager.addMapping("Rotate Left", new KeyTrigger(KeyInput.KEY_Q));
inputManager.addMapping("Rotate Right", new KeyTrigger(KeyInput.KEY_D));
inputManager.addMapping("Generic Mouse Action", new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
inputManager.addListener(this, "Rotate Left", "Rotate Right");
inputManager.addListener(this, "Forward", "Back");
inputManager.addListener(this, "Generic Mouse Action");
}
private void initTerrain() {
Material mat = new Material(assetManager, "Common/MatDefs/Terrain/Terrain.j3md");
mat.setTexture("Alpha", assetManager.loadTexture("terrain/alphamap.png"));
Texture grass = assetManager.loadTexture("terrain/grass.jpg");
grass.setWrap(WrapMode.Repeat);
mat.setTexture("Tex1", grass);
mat.setFloat("Tex1Scale", 64f);
Texture dirt = assetManager.loadTexture("terrain/dirt.jpg");
dirt.setWrap(WrapMode.Repeat);
mat.setTexture("Tex2", dirt);
mat.setFloat("Tex2Scale", 32f);
Texture rock = assetManager.loadTexture("terrain/road.jpg");
rock.setWrap(WrapMode.Repeat);
mat.setTexture("Tex3", rock);
mat.setFloat("Tex3Scale", 128f);
AbstractHeightMap heightmap = null;
Texture heightMapImage = assetManager.loadTexture("terrain/mountains512_2.png");
heightmap = new ImageBasedHeightMap(heightMapImage.getImage());
heightmap.load();
int patchSize = 65;
terrain = new TerrainQuad("TERRAIN_", patchSize, 513, heightmap.getHeightMap());
terrain.setMaterial(mat);
terrain.setLocalTranslation(0, -150, 0);
terrainNode.attachChild(terrain);
NavMeshUtils nmUtils = new NavMeshUtils(assetManager);
navMesh = nmUtils.buildNavMesh(terrainNode);
}
private void initNav(){
NavMeshUtils nmUtils = new NavMeshUtils(assetManager);
navMesh = nmUtils.buildNavMesh(terrainNode);
Geometry navGeometry = nmUtils.createNavMesh(terrainNode);
rootNode.attachChild(navGeometry);
}
private void initCamera() {
flyCam.setEnabled(false);
myCamera = new MyCamera(cam, player, inputManager);
myCamera.setSmoothMotion(false);
myCamera.setInvertVerticalAxis(true);
}
private void initPhysics(){
bulletAppState = new BulletAppState();
bulletAppState.setDebugEnabled(true);
stateManager.attach(bulletAppState);
RigidBodyControl floorControl = new RigidBodyControl(0f);
playerControl = new BetterCharacterControl(1.5f, 4, 30f);
playerNode.addControl(playerControl);
terrainNode.addControl(floorControl);
bulletAppState.getPhysicsSpace().add(playerNode);
bulletAppState.getPhysicsSpace().add(terrainNode);
}
public static void main(String[] args) {
MyGame game = new MyGame();
game.start();
}
}
NavMeshUtils.java
package fr.flow10000.akkad.utils;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import jme3tools.optimize.GeometryBatchFactory;
import com.jme3.ai.navmesh.NavMesh;
import com.jme3.asset.AssetManager;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
public class NavMeshUtils {
private AssetManager assetManager;
public NavMeshUtils(AssetManager assetManager){
this.assetManager = assetManager;
}
public NavMesh buildNavMesh(Node node){
Mesh mesh = new Mesh();
NavMesh navMesh = new NavMesh();
NavMeshGenerator generator = new NavMeshGenerator();
generator.setCellHeight(1f);
GeometryBatchFactory.mergeGeometries(findGeometries(node, new LinkedList<Geometry>()), mesh);
Mesh optiMesh = generator.optimize(mesh);
navMesh.loadFromMesh(optiMesh);
return navMesh;
}
public Geometry createNavMesh(Node node) {
Mesh mesh = new Mesh();
NavMesh navMesh = new NavMesh();
NavMeshGenerator generator = new NavMeshGenerator();
generator.setCellHeight(1f);
GeometryBatchFactory.mergeGeometries(findGeometries(node, new LinkedList<Geometry>()), mesh);
Mesh optiMesh = generator.optimize(mesh);
navMesh.loadFromMesh(optiMesh);
Geometry navGeom = new Geometry("NavMesh");
navGeom.setMesh(optiMesh);
Material green = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
green.setColor("Color", ColorRGBA.Green);
green.getAdditionalRenderState().setWireframe(true);
navGeom.setMaterial(green);
return navGeom;
}
private List<Geometry> findGeometries(Node node, List<Geometry> geoms) {
for (Iterator<Spatial> it = node.getChildren().iterator(); it.hasNext();) {
Spatial spatial = it.next();
if (spatial instanceof Geometry) {
geoms.add((Geometry) spatial);
} else if (spatial instanceof Node) {
findGeometries((Node) spatial, geoms);
}
}
return geoms;
}
}