@@ -26,6 +26,12 @@ public abstract class GameApplication extends NotSoSimpleApplication | |||
stateManager.attach(bulletAppState); | |||
} | |||
@Override | |||
public void update() { | |||
super.update(); | |||
updateListenerPosition(); | |||
} | |||
protected PhysicsSpace getPhysicsSpace(){ | |||
return bulletAppState.getPhysicsSpace(); | |||
} | |||
@@ -43,4 +49,10 @@ public abstract class GameApplication extends NotSoSimpleApplication | |||
{ | |||
bulletAppState.setEnabled(!paused); | |||
} | |||
protected void updateListenerPosition() | |||
{ | |||
listener.setLocation(cam.getLocation()); | |||
listener.setRotation(cam.getRotation()); | |||
} | |||
} |
@@ -153,6 +153,8 @@ public class RoadTrip extends GameApplication implements ActionListener { | |||
VehicleNode vehicle = new VehicleNode("Car " + vehicleInstance.toString(), vehicleInstance); | |||
vehicle.initialize(assetManager); | |||
vehicle.vehicleControl.setPhysicsLocation(new Vector3f(10f + (float)Math.random() * 40f, 228f, 12f + (float)Math.random() * 40f)); | |||
gameWorldState.vehicles.add(vehicle); | |||
getPhysicsSpace().addAll(vehicle); | |||
rootNode.attachChild(vehicle); | |||
@@ -169,7 +171,7 @@ public class RoadTrip extends GameApplication implements ActionListener { | |||
person.addControl(personControl); | |||
/**/personControl.setJumpForce(new Vector3f(0,5f,0)); | |||
personControl.setGravity(new Vector3f(0,1f,0)); | |||
personControl.warp(new Vector3f(10f + (float)Math.random() * 20f, 30f, 12f + (float)Math.random() * 20f));/**/ | |||
personControl.warp(new Vector3f(10f + (float)Math.random() * 20f, 230f, 12f + (float)Math.random() * 20f));/**/ | |||
//personControl.setPhysicsLocation(new Vector3f(10f, 30f, 12f)); | |||
getPhysicsSpace().add(personControl); | |||
//getPhysicsSpace().addAll(person); | |||
@@ -0,0 +1,77 @@ | |||
package roadtrip; | |||
import com.jme3.app.SimpleApplication; | |||
import com.jme3.audio.AudioNode; | |||
import com.jme3.audio.AudioSource.Status; | |||
import com.jme3.bullet.BulletAppState; | |||
import com.jme3.bullet.PhysicsSpace; | |||
import com.jme3.bullet.collision.shapes.*; | |||
import com.jme3.bullet.control.BetterCharacterControl; | |||
import com.jme3.bullet.control.RigidBodyControl; | |||
import com.jme3.bullet.control.VehicleControl; | |||
import com.jme3.font.BitmapFont; | |||
import com.jme3.font.BitmapText; | |||
import com.jme3.font.Rectangle; | |||
import com.jme3.input.ChaseCamera; | |||
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.material.Material; | |||
import com.jme3.math.*; | |||
import com.jme3.renderer.queue.RenderQueue; | |||
import com.jme3.scene.Geometry; | |||
import com.jme3.scene.Node; | |||
import com.jme3.scene.Spatial; | |||
import com.jme3.scene.debug.Arrow; | |||
import com.jme3.scene.shape.Box; | |||
import com.jme3.scene.shape.Cylinder; | |||
import com.jme3.terrain.geomipmap.TerrainGrid; | |||
import com.jme3.terrain.geomipmap.TerrainGridListener; | |||
import com.jme3.terrain.geomipmap.TerrainQuad; | |||
import java.util.Random; | |||
import roadtrip.model.VehicleInstance; | |||
import roadtrip.view.CompassNode; | |||
import roadtrip.view.GameMenuNode; | |||
import roadtrip.view.GameWorldView; | |||
import roadtrip.view.VehicleNode; | |||
import roadtrip.view.model.GameWorldState; | |||
import roadtrip.view.model.Player; | |||
/** | |||
* | |||
* @author dejvino | |||
*/ | |||
public class RoadTripPlanner extends SimpleApplication { | |||
public static void main(String[] args) { | |||
RoadTripPlanner app = new RoadTripPlanner(); | |||
app.start(); | |||
} | |||
public static boolean DEBUG = /*false;/*/true;/**/ | |||
protected BulletAppState bulletAppState; | |||
private GameWorldState gameWorldState; | |||
private GameWorldView gameWorldView; | |||
protected PhysicsSpace getPhysicsSpace(){ | |||
return bulletAppState.getPhysicsSpace(); | |||
} | |||
@Override | |||
public void simpleInitApp() | |||
{ | |||
bulletAppState = new BulletAppState(); | |||
stateManager.attach(bulletAppState); | |||
bulletAppState.setDebugEnabled(DEBUG); | |||
gameWorldState = new GameWorldState(1L); | |||
gameWorldView = GameWorldView.create(gameWorldState, assetManager, cam, rootNode, getPhysicsSpace()); | |||
flyCam.setMoveSpeed(300f); | |||
cam.setLocation(new Vector3f(0, 200f, 0)); | |||
} | |||
} |
@@ -0,0 +1,26 @@ | |||
package roadtrip.model; | |||
import com.jme3.math.Vector3f; | |||
/** | |||
* Created by dejvino on 21.01.2017. | |||
*/ | |||
public class MapObjectInstance | |||
{ | |||
private Vector3f position; | |||
public MapObjectInstance(Vector3f position) | |||
{ | |||
this.position = new Vector3f(position); | |||
} | |||
public Vector3f getPosition() | |||
{ | |||
return new Vector3f(position); | |||
} | |||
public void setPosition(Vector3f position) | |||
{ | |||
this.position = new Vector3f(position); | |||
} | |||
} |
@@ -1,5 +1,6 @@ | |||
package roadtrip.model; | |||
import com.jme3.terrain.geomipmap.TerrainQuad; | |||
import roadtrip.model.AbstractProceduralBlock; | |||
import roadtrip.model.ProceduralMapQuadBlock; | |||
@@ -13,8 +14,10 @@ public class ProceduralMapBlock extends AbstractProceduralBlock | |||
super(seed); | |||
} | |||
public ProceduralMapQuadBlock getMapQuadBlock(String quadName) | |||
public ProceduralMapQuadBlock getMapQuadBlock(TerrainQuad terrainQuad) | |||
{ | |||
return getSubBlock(quadName, ProceduralMapQuadBlock.class); | |||
ProceduralMapQuadBlock quadBlock = getSubBlock(terrainQuad.getName(), ProceduralMapQuadBlock.class); | |||
quadBlock.initialize(terrainQuad); | |||
return quadBlock; | |||
} | |||
} |
@@ -1,12 +1,56 @@ | |||
package roadtrip.model; | |||
import com.jme3.bullet.collision.shapes.ConeCollisionShape; | |||
import com.jme3.bullet.control.RigidBodyControl; | |||
import com.jme3.math.Vector2f; | |||
import com.jme3.math.Vector3f; | |||
import com.jme3.scene.Spatial; | |||
import com.jme3.terrain.geomipmap.TerrainQuad; | |||
import java.util.Collections; | |||
import java.util.LinkedList; | |||
import java.util.List; | |||
import java.util.Random; | |||
/** | |||
* Created by dejvino on 21.01.2017. | |||
*/ | |||
public class ProceduralMapQuadBlock extends AbstractProceduralBlock | |||
{ | |||
protected float cellSize = 64 * 2f * 2f; /* terrainGrid.getPatchSize() * terrainGrid.getLocalScale().x * 2f */ | |||
private List<MapObjectInstance> mapObjects; | |||
public ProceduralMapQuadBlock(long seed) | |||
{ | |||
super(seed); | |||
} | |||
public void initialize(TerrainQuad terrainQuad) | |||
{ | |||
mapObjects = new LinkedList<>(); | |||
Random quadRand = getBlockRandom(); | |||
Vector2f prevPos = null; | |||
Vector2f quadPos = new Vector2f(terrainQuad.getLocalTranslation().x, terrainQuad.getLocalTranslation().z); | |||
for (int i = 0; i < quadRand.nextInt(10000); i++) { | |||
Vector2f pos; | |||
if (prevPos == null || quadRand.nextFloat() < 0.2f) { | |||
pos = new Vector2f((quadRand.nextFloat() - 0.5f) * cellSize, (quadRand.nextFloat() - 0.5f) * cellSize) | |||
.addLocal(quadPos); | |||
} else { | |||
pos = new Vector2f((quadRand.nextFloat() - 0.5f) * 20f, (quadRand.nextFloat() - 0.5f) * 20f) | |||
.addLocal(prevPos); | |||
} | |||
prevPos = pos; | |||
float height = terrainQuad.getHeight(pos); | |||
Vector3f location = new Vector3f(pos.x, height, pos.y); | |||
mapObjects.add(new MapObjectInstance(location)); | |||
} | |||
} | |||
public Iterable<? extends MapObjectInstance> getMapObjects() | |||
{ | |||
if (mapObjects == null) throw new RuntimeException("Call to getMapObjects on an uninitialized block."); | |||
return mapObjects; | |||
} | |||
} |
@@ -5,8 +5,10 @@ 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.light.AmbientLight; | |||
import com.jme3.light.DirectionalLight; | |||
import com.jme3.material.Material; | |||
import com.jme3.math.Vector2f; | |||
import com.jme3.math.ColorRGBA; | |||
import com.jme3.math.Vector3f; | |||
import com.jme3.renderer.Camera; | |||
import com.jme3.scene.Node; | |||
@@ -23,12 +25,11 @@ 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.MapObjectInstance; | |||
import roadtrip.model.ProceduralMapQuadBlock; | |||
import roadtrip.model.TerrainDataProvider; | |||
import roadtrip.view.model.GameWorldState; | |||
import java.util.Random; | |||
/** | |||
* Created by dejvino on 14.01.2017. | |||
*/ | |||
@@ -59,6 +60,15 @@ public class GameWorldView { | |||
private void initialize() | |||
{ | |||
// Environment | |||
DirectionalLight dl = new DirectionalLight(); | |||
dl.setColor(ColorRGBA.LightGray); | |||
dl.setDirection(new Vector3f(1, -1, 1)); | |||
rootNode.addLight(dl); | |||
AmbientLight al = new AmbientLight(); | |||
al.setColor(new ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f)); | |||
rootNode.addLight(al); | |||
// TERRAIN TEXTURE material | |||
terrain.mat_terrain = new Material(assetManager, "Common/MatDefs/Terrain/HeightBasedTerrain.j3md"); | |||
@@ -133,15 +143,15 @@ public class GameWorldView { | |||
ground.addPreFilter(terrain.terrainDataProvider.iterate); | |||
terrain.terrainGrid = new TerrainGrid("terrain", 64 + 1, 256 + 1, new FractalTileLoader(ground, 300f)); | |||
terrain.terrainGrid = new TerrainGrid("terrain", 16 + 1, 512 + 1, new FractalTileLoader(ground, 300f)); | |||
terrain.terrainGrid.setMaterial(terrain.mat_terrain); | |||
terrain.terrainGrid.setLocalTranslation(0, -200, 0); | |||
terrain.terrainGrid.setLocalScale(2f, 1f, 2f); | |||
//terrain.terrainGrid.setLocalTranslation(0, -200, 0); | |||
//terrain.terrainGrid.setLocalScale(2f, 1f, 2f); | |||
this.rootNode.attachChild(terrain.terrainGrid); | |||
TerrainLodControl control = new TerrainGridLodControl(terrain.terrainGrid, camera); | |||
control.setLodCalculator(new DistanceLodCalculator(64 + 1, 2.7f)); // patch size, and a multiplier | |||
control.setLodCalculator(new DistanceLodCalculator(32 + 1, 2.7f)); // patch size, and a multiplier | |||
terrain.terrainGrid.addControl(control); | |||
final TerrainGrid terrainGrid = terrain.terrainGrid; | |||
@@ -163,48 +173,33 @@ public class GameWorldView { | |||
String quadObjectsNodeKey = getQuadObjectsNodeKey(quad); | |||
Node objects = new Node(quadObjectsNodeKey); | |||
populateQuadObjectsNode(quad, quadObjectsNodeKey, objects); | |||
populateQuadObjectsNode(quad, objects); | |||
rootNode.attachChild(objects); | |||
} | |||
protected void populateQuadObjectsNode(TerrainQuad quad, String quadObjectsNodeKey, Node objects) | |||
protected void populateQuadObjectsNode(TerrainQuad quad, Node objects) | |||
{ | |||
ProceduralMapQuadBlock mapQuadBlock = state.proceduralMap.getMapQuadBlock(quad.getName()); | |||
// TODO: move any access to the Random into the ProceduralMapQuadBlock | |||
Random quadRand = mapQuadBlock.getBlockRandom(); | |||
ProceduralMapQuadBlock mapQuadBlock = state.proceduralMap.getMapQuadBlock(quad); | |||
// Generate trees | |||
// Add map objects (for now - 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; | |||
Vector2f prevPos = null; | |||
for (int i = 0; i < quadRand.nextInt(10000); i++) { | |||
Vector2f pos; | |||
if (prevPos == null || quadRand.nextFloat() < 0.2f) { | |||
pos = new Vector2f((quadRand.nextFloat() - 0.5f) * cellSize, (quadRand.nextFloat() - 0.5f) * cellSize) | |||
.addLocal(quad.getWorldTranslation().x, quad.getWorldTranslation().z); | |||
} else { | |||
pos = new Vector2f((quadRand.nextFloat() - 0.5f) * 20f, (quadRand.nextFloat() - 0.5f) * 20f).addLocal(prevPos); | |||
} | |||
prevPos = pos; | |||
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); | |||
for (MapObjectInstance mapObject : mapQuadBlock.getMapObjects()) { | |||
Vector3f pos = mapObject.getPosition(); | |||
Spatial modelInstance = treeModel.clone(); | |||
modelInstance.setLocalTranslation(pos); | |||
// 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); | |||
modelInstance.addControl(control); | |||
control.setPhysicsLocation(pos); | |||
physicsSpace.add(control); | |||
} | |||
objects.attachChild(treeInstance); | |||
objects.attachChild(modelInstance); | |||
} | |||
//objects.setLocalTranslation(terrainGrid.getWorldTranslation()); | |||
} | |||
@Override | |||
@@ -213,7 +213,6 @@ public class VehicleNode extends Node | |||
vehicle.attachChild(vehicle.wheelSlipAudio); | |||
vehicle.addControl(vehicleControl); | |||
vehicleControl.setPhysicsLocation(new Vector3f(10f + (float)Math.random() * 40f, 28f, 12f + (float)Math.random() * 40f)); | |||
} | |||
public void update(float tpf) | |||