1 package jme3test.terrain; 2 3 import com.jme3.app.SimpleApplication; 4 import com.jme3.app.state.ScreenshotAppState; 5 import com.jme3.asset.plugins.HttpZipLocator; 6 import com.jme3.asset.plugins.ZipLocator; 7 import com.jme3.bullet.BulletAppState; 8 import com.jme3.bullet.collision.shapes.CapsuleCollisionShape; 9 import com.jme3.bullet.collision.shapes.HeightfieldCollisionShape; 10 import com.jme3.bullet.control.CharacterControl; 11 import com.jme3.bullet.control.RigidBodyControl; 12 import com.jme3.input.KeyInput; 13 import com.jme3.input.controls.ActionListener; 14 import com.jme3.input.controls.KeyTrigger; 15 import com.jme3.light.DirectionalLight; 16 import com.jme3.material.Material; 17 import com.jme3.math.ColorRGBA; 18 import com.jme3.math.Vector3f; 19 import com.jme3.terrain.geomipmap.TerrainGrid; 20 import com.jme3.terrain.geomipmap.TerrainGridListener; 21 import com.jme3.terrain.geomipmap.TerrainLodControl; 22 import com.jme3.terrain.geomipmap.TerrainQuad; 23 import com.jme3.terrain.geomipmap.grid.ImageTileLoader; 24 import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator; 25 import com.jme3.terrain.heightmap.Namer; 26 import com.jme3.texture.Texture; 27 import com.jme3.texture.Texture.WrapMode; 28 import java.io.File; 29 30 public class TerrainGridTest extends SimpleApplication { 31 32 private Material mat_terrain; 33 private TerrainGrid terrain; 34 private float grassScale = 64; 35 private float dirtScale = 16; 36 private float rockScale = 128; 37 private boolean usePhysics = false; 38 private boolean physicsAdded = false; 39 main(final String[] args)40 public static void main(final String[] args) { 41 TerrainGridTest app = new TerrainGridTest(); 42 app.start(); 43 } 44 private CharacterControl player3; 45 46 @Override simpleInitApp()47 public void simpleInitApp() { 48 File file = new File("TerrainGridTestData.zip"); 49 if (!file.exists()) { 50 assetManager.registerLocator("http://jmonkeyengine.googlecode.com/files/TerrainGridTestData.zip", HttpZipLocator.class); 51 } else { 52 assetManager.registerLocator("TerrainGridTestData.zip", ZipLocator.class); 53 } 54 55 this.flyCam.setMoveSpeed(100f); 56 ScreenshotAppState state = new ScreenshotAppState(); 57 this.stateManager.attach(state); 58 59 // TERRAIN TEXTURE material 60 this.mat_terrain = new Material(this.assetManager, "Common/MatDefs/Terrain/HeightBasedTerrain.j3md"); 61 62 // Parameters to material: 63 // regionXColorMap: X = 1..4 the texture that should be appliad to state X 64 // regionX: a Vector3f containing the following information: 65 // regionX.x: the start height of the region 66 // regionX.y: the end height of the region 67 // regionX.z: the texture scale for the region 68 // it might not be the most elegant way for storing these 3 values, but it packs the data nicely :) 69 // slopeColorMap: the texture to be used for cliffs, and steep mountain sites 70 // slopeTileFactor: the texture scale for slopes 71 // terrainSize: the total size of the terrain (used for scaling the texture) 72 // GRASS texture 73 Texture grass = this.assetManager.loadTexture("Textures/Terrain/splat/grass.jpg"); 74 grass.setWrap(WrapMode.Repeat); 75 this.mat_terrain.setTexture("region1ColorMap", grass); 76 this.mat_terrain.setVector3("region1", new Vector3f(88, 200, this.grassScale)); 77 78 // DIRT texture 79 Texture dirt = this.assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg"); 80 dirt.setWrap(WrapMode.Repeat); 81 this.mat_terrain.setTexture("region2ColorMap", dirt); 82 this.mat_terrain.setVector3("region2", new Vector3f(0, 90, this.dirtScale)); 83 84 // ROCK texture 85 Texture rock = this.assetManager.loadTexture("Textures/Terrain/Rock2/rock.jpg"); 86 rock.setWrap(WrapMode.Repeat); 87 this.mat_terrain.setTexture("region3ColorMap", rock); 88 this.mat_terrain.setVector3("region3", new Vector3f(198, 260, this.rockScale)); 89 90 this.mat_terrain.setTexture("region4ColorMap", rock); 91 this.mat_terrain.setVector3("region4", new Vector3f(198, 260, this.rockScale)); 92 93 this.mat_terrain.setTexture("slopeColorMap", rock); 94 this.mat_terrain.setFloat("slopeTileFactor", 32); 95 96 this.mat_terrain.setFloat("terrainSize", 129); 97 98 this.terrain = new TerrainGrid("terrain", 65, 257, new ImageTileLoader(assetManager, new Namer() { 99 100 public String getName(int x, int y) { 101 return "Scenes/TerrainMountains/terrain_" + x + "_" + y + ".png"; 102 } 103 })); 104 105 this.terrain.setMaterial(mat_terrain); 106 this.terrain.setLocalTranslation(0, 0, 0); 107 this.terrain.setLocalScale(1f, 1f, 1f); 108 this.rootNode.attachChild(this.terrain); 109 110 TerrainLodControl control = new TerrainLodControl(this.terrain, getCamera()); 111 control.setLodCalculator( new DistanceLodCalculator(65, 2.7f) ); // patch size, and a multiplier 112 this.terrain.addControl(control); 113 114 final BulletAppState bulletAppState = new BulletAppState(); 115 stateManager.attach(bulletAppState); 116 117 this.getCamera().setLocation(new Vector3f(0, 200, 0)); 118 119 this.viewPort.setBackgroundColor(new ColorRGBA(0.7f, 0.8f, 1f, 1f)); 120 121 DirectionalLight light = new DirectionalLight(); 122 light.setDirection((new Vector3f(-0.5f, -1f, -0.5f)).normalize()); 123 rootNode.addLight(light); 124 125 if (usePhysics) { 126 CapsuleCollisionShape capsuleShape = new CapsuleCollisionShape(0.5f, 1.8f, 1); 127 player3 = new CharacterControl(capsuleShape, 0.5f); 128 player3.setJumpSpeed(20); 129 player3.setFallSpeed(10); 130 player3.setGravity(10); 131 132 player3.setPhysicsLocation(new Vector3f(cam.getLocation().x, 256, cam.getLocation().z)); 133 134 bulletAppState.getPhysicsSpace().add(player3); 135 136 terrain.addListener(new TerrainGridListener() { 137 138 public void gridMoved(Vector3f newCenter) { 139 } 140 141 public Material tileLoaded(Material material, Vector3f cell) { 142 return material; 143 } 144 145 public void tileAttached(Vector3f cell, TerrainQuad quad) { 146 while(quad.getControl(RigidBodyControl.class)!=null){ 147 quad.removeControl(RigidBodyControl.class); 148 } 149 quad.addControl(new RigidBodyControl(new HeightfieldCollisionShape(quad.getHeightMap(), terrain.getLocalScale()), 0)); 150 bulletAppState.getPhysicsSpace().add(quad); 151 } 152 153 public void tileDetached(Vector3f cell, TerrainQuad quad) { 154 bulletAppState.getPhysicsSpace().remove(quad); 155 quad.removeControl(RigidBodyControl.class); 156 } 157 158 }); 159 } 160 161 this.initKeys(); 162 } 163 initKeys()164 private void initKeys() { 165 // You can map one or several inputs to one named action 166 this.inputManager.addMapping("Lefts", new KeyTrigger(KeyInput.KEY_A)); 167 this.inputManager.addMapping("Rights", new KeyTrigger(KeyInput.KEY_D)); 168 this.inputManager.addMapping("Ups", new KeyTrigger(KeyInput.KEY_W)); 169 this.inputManager.addMapping("Downs", new KeyTrigger(KeyInput.KEY_S)); 170 this.inputManager.addMapping("Jumps", new KeyTrigger(KeyInput.KEY_SPACE)); 171 this.inputManager.addListener(this.actionListener, "Lefts"); 172 this.inputManager.addListener(this.actionListener, "Rights"); 173 this.inputManager.addListener(this.actionListener, "Ups"); 174 this.inputManager.addListener(this.actionListener, "Downs"); 175 this.inputManager.addListener(this.actionListener, "Jumps"); 176 } 177 private boolean left; 178 private boolean right; 179 private boolean up; 180 private boolean down; 181 private final ActionListener actionListener = new ActionListener() { 182 183 @Override 184 public void onAction(final String name, final boolean keyPressed, final float tpf) { 185 if (name.equals("Lefts")) { 186 if (keyPressed) { 187 TerrainGridTest.this.left = true; 188 } else { 189 TerrainGridTest.this.left = false; 190 } 191 } else if (name.equals("Rights")) { 192 if (keyPressed) { 193 TerrainGridTest.this.right = true; 194 } else { 195 TerrainGridTest.this.right = false; 196 } 197 } else if (name.equals("Ups")) { 198 if (keyPressed) { 199 TerrainGridTest.this.up = true; 200 } else { 201 TerrainGridTest.this.up = false; 202 } 203 } else if (name.equals("Downs")) { 204 if (keyPressed) { 205 TerrainGridTest.this.down = true; 206 } else { 207 TerrainGridTest.this.down = false; 208 } 209 } else if (name.equals("Jumps")) { 210 TerrainGridTest.this.player3.jump(); 211 } 212 } 213 }; 214 private final Vector3f walkDirection = new Vector3f(); 215 216 @Override simpleUpdate(final float tpf)217 public void simpleUpdate(final float tpf) { 218 Vector3f camDir = this.cam.getDirection().clone().multLocal(0.6f); 219 Vector3f camLeft = this.cam.getLeft().clone().multLocal(0.4f); 220 this.walkDirection.set(0, 0, 0); 221 if (this.left) { 222 this.walkDirection.addLocal(camLeft); 223 } 224 if (this.right) { 225 this.walkDirection.addLocal(camLeft.negate()); 226 } 227 if (this.up) { 228 this.walkDirection.addLocal(camDir); 229 } 230 if (this.down) { 231 this.walkDirection.addLocal(camDir.negate()); 232 } 233 234 if (usePhysics) { 235 this.player3.setWalkDirection(this.walkDirection); 236 this.cam.setLocation(this.player3.getPhysicsLocation()); 237 } 238 } 239 } 240