diff --git a/src/roadtrip/RoadTrip.java b/src/roadtrip/RoadTrip.java index c57d35d..c6805b1 100644 --- a/src/roadtrip/RoadTrip.java +++ b/src/roadtrip/RoadTrip.java @@ -90,71 +90,9 @@ public class RoadTrip extends GameApplication implements ActionListener { al.setColor(new ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f)); rootNode.addLight(al); - gameWorldState = new GameWorldState(); - gameWorldView = GameWorldView.create(gameWorldState, assetManager, cam, rootNode); - final TerrainGrid terrainGrid = gameWorldView.terrain.terrainGrid; - terrainGrid.addListener(new TerrainGridListener() { + gameWorldState = new GameWorldState(1L); + gameWorldView = GameWorldView.create(gameWorldState, assetManager, cam, rootNode, getPhysicsSpace()); - @Override - public void gridMoved(Vector3f newCenter) { - } - - @Override - public void tileAttached(Vector3f cell, TerrainQuad quad) { - while(quad.getControl(RigidBodyControl.class)!=null){ - quad.removeControl(RigidBodyControl.class); - } - quad.addControl(new RigidBodyControl(new HeightfieldCollisionShape(quad.getHeightMap(), terrainGrid.getLocalScale()), 0)); - getPhysicsSpace().add(quad); - - String treesKey = "trees-" + quad.getName(); - Spatial treesOld = rootNode.getChild(treesKey); - if (treesOld != null) { - getPhysicsSpace().removeAll(treesOld); - treesOld.removeFromParent(); - } - - Node trees = new Node(treesKey); - Random quadRand = new Random(treesKey.hashCode()); - Spatial treeModel = assetManager.loadModel("Models/tree.j3o"); - System.out.println("Grid @ " + terrainGrid.getLocalTranslation() + " s " + terrainGrid.getLocalScale()); - System.out.println("Quad " + quad.getName() + " @ " + quad.getLocalTranslation()); - float cellSize = terrainGrid.getPatchSize() * terrainGrid.getLocalScale().x * 2f; - for (int i = 0; i < quadRand.nextInt(1000); i++) { - Vector2f pos = new Vector2f((quadRand.nextFloat() - 0.5f) * cellSize, (quadRand.nextFloat() - 0.5f) * cellSize) - .addLocal(quad.getWorldTranslation().x, quad.getWorldTranslation().z); - float height = quad.getHeight(pos); - Vector3f location = new Vector3f(pos.x, height, pos.y) - .addLocal(terrainGrid.getWorldTranslation()); - System.out.println("Tree " + i + ": " + location); - Spatial treeInstance = treeModel.clone(); - treeInstance.setLocalTranslation(location); - //RigidBodyControl control = treeInstance.getControl(RigidBodyControl.class); - RigidBodyControl control = new RigidBodyControl(new ConeCollisionShape(1f, 5f), 0f); - if (control != null) { - treeInstance.addControl(control); - control.setPhysicsLocation(location); - getPhysicsSpace().add(control); - } - trees.attachChild(treeInstance); - } - rootNode.attachChild(trees); - } - - @Override - public void tileDetached(Vector3f cell, TerrainQuad quad) { - if (quad.getControl(RigidBodyControl.class) != null) { - getPhysicsSpace().remove(quad); - quad.removeControl(RigidBodyControl.class); - String treesKey = "trees-" + quad.getName(); - Spatial trees = rootNode.getChild(treesKey); - getPhysicsSpace().removeAll(trees); - trees.removeFromParent(); - } - } - - }); - addCar(); addCar(); addCar(); @@ -172,7 +110,7 @@ public class RoadTrip extends GameApplication implements ActionListener { addTarget(); addCompass(); - addGameMenu(); + addGameMenu(); chaseCam = new ChaseCamera(cam, player.node, inputManager); chaseCam.setDefaultDistance(60f); diff --git a/src/roadtrip/model/AbstractProceduralBlock.java b/src/roadtrip/model/AbstractProceduralBlock.java index 909cf9b..f7d445d 100644 --- a/src/roadtrip/model/AbstractProceduralBlock.java +++ b/src/roadtrip/model/AbstractProceduralBlock.java @@ -39,7 +39,7 @@ public abstract class AbstractProceduralBlock implements ProceduralBlock { if (subBlockClass == null) throw new NullPointerException("subBlockClass"); try { - Constructor constructor = subBlockClass.getConstructor(Long.class); + Constructor constructor = subBlockClass.getConstructor(Long.TYPE); return constructor.newInstance(getSubBlockSeed(subBlockKey)); } catch (NoSuchMethodException e) { throw new IllegalArgumentException("Class " + subBlockClass + " does not have the default constructor with a single 'long' parameter.", e); diff --git a/src/roadtrip/model/ProceduralMapQuadBlock.java b/src/roadtrip/model/ProceduralMapQuadBlock.java new file mode 100644 index 0000000..b9e772a --- /dev/null +++ b/src/roadtrip/model/ProceduralMapQuadBlock.java @@ -0,0 +1,12 @@ +package roadtrip.model; + +/** + * Created by dejvino on 21.01.2017. + */ +public class ProceduralMapQuadBlock extends AbstractProceduralBlock +{ + public ProceduralMapQuadBlock(long seed) + { + super(seed); + } +} diff --git a/src/roadtrip/view/GameWorldView.java b/src/roadtrip/view/GameWorldView.java index c2d055d..eb429fc 100644 --- a/src/roadtrip/view/GameWorldView.java +++ b/src/roadtrip/view/GameWorldView.java @@ -1,12 +1,16 @@ package roadtrip.view; import com.jme3.asset.AssetManager; +import com.jme3.bullet.PhysicsSpace; +import com.jme3.bullet.collision.shapes.ConeCollisionShape; import com.jme3.bullet.collision.shapes.HeightfieldCollisionShape; import com.jme3.bullet.control.RigidBodyControl; import com.jme3.material.Material; +import com.jme3.math.Vector2f; import com.jme3.math.Vector3f; import com.jme3.renderer.Camera; import com.jme3.scene.Node; +import com.jme3.scene.Spatial; import com.jme3.terrain.geomipmap.*; import com.jme3.terrain.geomipmap.grid.FractalTileLoader; import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator; @@ -19,31 +23,36 @@ import com.jme3.terrain.noise.filter.SmoothFilter; import com.jme3.terrain.noise.fractal.FractalSum; import com.jme3.terrain.noise.modulator.NoiseModulator; import com.jme3.texture.Texture; +import roadtrip.model.ProceduralMapQuadBlock; import roadtrip.model.TerrainDataProvider; import roadtrip.view.model.GameWorldState; +import java.util.Random; + /** * Created by dejvino on 14.01.2017. */ public class GameWorldView { - private GameWorldState state; + private final GameWorldState state; - private AssetManager assetManager; - private Camera camera; - private Node rootNode; + private final AssetManager assetManager; + private final Camera camera; + private final Node rootNode; + private final PhysicsSpace physicsSpace; public TerrainView terrain = new TerrainView(new TerrainDataProvider()); - public GameWorldView(GameWorldState gameWorldState, AssetManager assetManager, Camera camera, Node rootNode) { + public GameWorldView(GameWorldState gameWorldState, AssetManager assetManager, Camera camera, Node rootNode, PhysicsSpace physicsSpace) { this.state = gameWorldState; this.assetManager = assetManager; this.camera = camera; this.rootNode = rootNode; + this.physicsSpace = physicsSpace; } - public static GameWorldView create(GameWorldState gameWorldState, AssetManager assetManager, Camera camera, Node rootNode) { - GameWorldView gameWorldView = new GameWorldView(gameWorldState, assetManager, camera, rootNode); + public static GameWorldView create(GameWorldState gameWorldState, AssetManager assetManager, Camera camera, Node rootNode, PhysicsSpace physicsSpace) { + GameWorldView gameWorldView = new GameWorldView(gameWorldState, assetManager, camera, rootNode, physicsSpace); gameWorldView.initialize(); return gameWorldView; } @@ -134,5 +143,88 @@ public class GameWorldView { TerrainLodControl control = new TerrainGridLodControl(terrain.terrainGrid, camera); control.setLodCalculator(new DistanceLodCalculator(64 + 1, 2.7f)); // patch size, and a multiplier terrain.terrainGrid.addControl(control); + + final TerrainGrid terrainGrid = terrain.terrainGrid; + terrainGrid.addListener(new TerrainGridListener() { + + @Override + public void gridMoved(Vector3f newCenter) { + } + + @Override + public void tileAttached(Vector3f cell, TerrainQuad quad) { + while(quad.getControl(RigidBodyControl.class)!=null){ + quad.removeControl(RigidBodyControl.class); + } + quad.addControl(new RigidBodyControl(new HeightfieldCollisionShape(quad.getHeightMap(), terrainGrid.getLocalScale()), 0)); + physicsSpace.add(quad); + + removeQuadObjectsNode(quad); + + String quadObjectsNodeKey = getQuadObjectsNodeKey(quad); + Node objects = new Node(quadObjectsNodeKey); + populateQuadObjectsNode(quad, quadObjectsNodeKey, objects); + rootNode.attachChild(objects); + } + + protected void populateQuadObjectsNode(TerrainQuad quad, String quadObjectsNodeKey, Node objects) + { + ProceduralMapQuadBlock mapQuadBlock = state.proceduralMap.getMapQuadBlock(quad.getName()); + + // TODO: move any access to the Random into the ProceduralMapQuadBlock + Random quadRand = mapQuadBlock.getBlockRandom(); + + // Generate trees + Spatial treeModel = assetManager.loadModel("Models/tree.j3o"); + //System.out.println("Grid @ " + terrainGrid.getLocalTranslation() + " s " + terrainGrid.getLocalScale()); + //System.out.println("Quad " + quad.getName() + " @ " + quad.getLocalTranslation()); + float cellSize = terrainGrid.getPatchSize() * terrainGrid.getLocalScale().x * 2f; + for (int i = 0; i < quadRand.nextInt(1000); i++) { + Vector2f pos = new Vector2f((quadRand.nextFloat() - 0.5f) * cellSize, (quadRand.nextFloat() - 0.5f) * cellSize) + .addLocal(quad.getWorldTranslation().x, quad.getWorldTranslation().z); + float height = quad.getHeight(pos); + Vector3f location = new Vector3f(pos.x, height, pos.y) + .addLocal(terrainGrid.getWorldTranslation()); + System.out.println("Tree " + i + ": " + location); + Spatial treeInstance = treeModel.clone(); + treeInstance.setLocalTranslation(location); + // TODO: physics from the model and not hard-coded + //RigidBodyControl control = treeInstance.getControl(RigidBodyControl.class); + RigidBodyControl control = new RigidBodyControl(new ConeCollisionShape(1f, 5f), 0f); + if (control != null) { + treeInstance.addControl(control); + control.setPhysicsLocation(location); + physicsSpace.add(control); + } + objects.attachChild(treeInstance); + } + } + + @Override + public void tileDetached(Vector3f cell, TerrainQuad quad) { + if (quad.getControl(RigidBodyControl.class) != null) { + physicsSpace.remove(quad); + quad.removeControl(RigidBodyControl.class); + } + removeQuadObjectsNode(quad); + } + + protected void removeQuadObjectsNode(TerrainQuad quad) + { + Spatial quadObjectsNodeOld = rootNode.getChild(getQuadObjectsNodeKey(quad)); + if (quadObjectsNodeOld != null) { + physicsSpace.removeAll(quadObjectsNodeOld); + quadObjectsNodeOld.removeFromParent(); + } + } + + private String getQuadObjectsNodeKey(TerrainQuad quad) + { + return "Objects-" + quad.getName(); + } + + }); + } + } diff --git a/src/roadtrip/view/model/GameWorldState.java b/src/roadtrip/view/model/GameWorldState.java index 27b571e..c50c30d 100644 --- a/src/roadtrip/view/model/GameWorldState.java +++ b/src/roadtrip/view/model/GameWorldState.java @@ -8,6 +8,13 @@ import java.util.List; /** * Created by dejvino on 14.01.2017. */ -public class GameWorldState { - public List vehicles = new LinkedList<>(); +public class GameWorldState +{ + public final ProceduralMapBlock proceduralMap; + public final List vehicles = new LinkedList<>(); + + public GameWorldState(long worldSeed) + { + this.proceduralMap = new ProceduralMapBlock(worldSeed); + } } diff --git a/src/roadtrip/view/model/ProceduralMapBlock.java b/src/roadtrip/view/model/ProceduralMapBlock.java new file mode 100644 index 0000000..112c640 --- /dev/null +++ b/src/roadtrip/view/model/ProceduralMapBlock.java @@ -0,0 +1,20 @@ +package roadtrip.view.model; + +import roadtrip.model.AbstractProceduralBlock; +import roadtrip.model.ProceduralMapQuadBlock; + +/** + * Created by dejvino on 21.01.2017. + */ +public class ProceduralMapBlock extends AbstractProceduralBlock +{ + public ProceduralMapBlock(long seed) + { + super(seed); + } + + public ProceduralMapQuadBlock getMapQuadBlock(String quadName) + { + return getSubBlock(quadName, ProceduralMapQuadBlock.class); + } +}