1
0
mirror of https://github.com/Dejvino/roadtrip synced 2024-11-14 13:03:28 +00:00

Map: refactored populating of map objects to use the new procedural blocks.

This commit is contained in:
Dejvino 2017-01-21 18:47:47 +01:00
parent 7893ff412b
commit 4a87dbc674
6 changed files with 144 additions and 75 deletions

View File

@ -90,70 +90,8 @@ public class RoadTrip extends GameApplication implements ActionListener {
al.setColor(new ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f)); al.setColor(new ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f));
rootNode.addLight(al); rootNode.addLight(al);
gameWorldState = new GameWorldState(); gameWorldState = new GameWorldState(1L);
gameWorldView = GameWorldView.create(gameWorldState, assetManager, cam, rootNode); gameWorldView = GameWorldView.create(gameWorldState, assetManager, cam, rootNode, getPhysicsSpace());
final TerrainGrid terrainGrid = gameWorldView.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));
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(); addCar();

View File

@ -39,7 +39,7 @@ public abstract class AbstractProceduralBlock implements ProceduralBlock
{ {
if (subBlockClass == null) throw new NullPointerException("subBlockClass"); if (subBlockClass == null) throw new NullPointerException("subBlockClass");
try { try {
Constructor<T> constructor = subBlockClass.getConstructor(Long.class); Constructor<T> constructor = subBlockClass.getConstructor(Long.TYPE);
return constructor.newInstance(getSubBlockSeed(subBlockKey)); return constructor.newInstance(getSubBlockSeed(subBlockKey));
} catch (NoSuchMethodException e) { } catch (NoSuchMethodException e) {
throw new IllegalArgumentException("Class " + subBlockClass + " does not have the default constructor with a single 'long' parameter.", e); throw new IllegalArgumentException("Class " + subBlockClass + " does not have the default constructor with a single 'long' parameter.", e);

View File

@ -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);
}
}

View File

@ -1,12 +1,16 @@
package roadtrip.view; package roadtrip.view;
import com.jme3.asset.AssetManager; 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.collision.shapes.HeightfieldCollisionShape;
import com.jme3.bullet.control.RigidBodyControl; import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.material.Material; import com.jme3.material.Material;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera; import com.jme3.renderer.Camera;
import com.jme3.scene.Node; import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.terrain.geomipmap.*; import com.jme3.terrain.geomipmap.*;
import com.jme3.terrain.geomipmap.grid.FractalTileLoader; import com.jme3.terrain.geomipmap.grid.FractalTileLoader;
import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator; 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.fractal.FractalSum;
import com.jme3.terrain.noise.modulator.NoiseModulator; import com.jme3.terrain.noise.modulator.NoiseModulator;
import com.jme3.texture.Texture; import com.jme3.texture.Texture;
import roadtrip.model.ProceduralMapQuadBlock;
import roadtrip.model.TerrainDataProvider; import roadtrip.model.TerrainDataProvider;
import roadtrip.view.model.GameWorldState; import roadtrip.view.model.GameWorldState;
import java.util.Random;
/** /**
* Created by dejvino on 14.01.2017. * Created by dejvino on 14.01.2017.
*/ */
public class GameWorldView { public class GameWorldView {
private GameWorldState state; private final GameWorldState state;
private AssetManager assetManager; private final AssetManager assetManager;
private Camera camera; private final Camera camera;
private Node rootNode; private final Node rootNode;
private final PhysicsSpace physicsSpace;
public TerrainView terrain = new TerrainView(new TerrainDataProvider()); 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.state = gameWorldState;
this.assetManager = assetManager; this.assetManager = assetManager;
this.camera = camera; this.camera = camera;
this.rootNode = rootNode; this.rootNode = rootNode;
this.physicsSpace = physicsSpace;
} }
public static GameWorldView create(GameWorldState gameWorldState, AssetManager assetManager, Camera camera, Node rootNode) { public static GameWorldView create(GameWorldState gameWorldState, AssetManager assetManager, Camera camera, Node rootNode, PhysicsSpace physicsSpace) {
GameWorldView gameWorldView = new GameWorldView(gameWorldState, assetManager, camera, rootNode); GameWorldView gameWorldView = new GameWorldView(gameWorldState, assetManager, camera, rootNode, physicsSpace);
gameWorldView.initialize(); gameWorldView.initialize();
return gameWorldView; return gameWorldView;
} }
@ -134,5 +143,88 @@ public class GameWorldView {
TerrainLodControl control = new TerrainGridLodControl(terrain.terrainGrid, camera); TerrainLodControl control = new TerrainGridLodControl(terrain.terrainGrid, camera);
control.setLodCalculator(new DistanceLodCalculator(64 + 1, 2.7f)); // patch size, and a multiplier control.setLodCalculator(new DistanceLodCalculator(64 + 1, 2.7f)); // patch size, and a multiplier
terrain.terrainGrid.addControl(control); 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();
}
});
}
}

View File

@ -8,6 +8,13 @@ import java.util.List;
/** /**
* Created by dejvino on 14.01.2017. * Created by dejvino on 14.01.2017.
*/ */
public class GameWorldState { public class GameWorldState
public List<VehicleNode> vehicles = new LinkedList<>(); {
public final ProceduralMapBlock proceduralMap;
public final List<VehicleNode> vehicles = new LinkedList<>();
public GameWorldState(long worldSeed)
{
this.proceduralMap = new ProceduralMapBlock(worldSeed);
}
} }

View File

@ -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);
}
}