Can TerraMonkey do this......?

Hey Guys,



I am a new and up’n’coming Game Developer. I have read about the TerrainGrid’s ability to Generate Terrain infinitely. I was wondering if there was a way during the way I could randomly generate the terrain, If so how would I do it? I also was wondering if during the generation of the Height Map could I also use it to generate where the textures would go (For example for Height Map Values 255 to 245 use Snowy Rock, for Values of 244 to 120 use rocky, for values 120 to 50 use Grassy, from 50 to 0 use sand.)? Then based off of the Height Map could I adjust the mesh in the TerrainPatch so I could place things that I want (For example, that there was an area on the Height map that was in a range that is favorable for a placement of a Quarry mesh, could I adjust the Underlying Mesh and lower it, then on top of it place the Quarry Mesh on top.)?



I am not a novice Java Programmer, I have a few years behind me. I have finished all the Hello… tutorials. I am always willing to learn something new, I only look for a person who is willing to teach me. I don’t want you to give me code, but steps would be nice.



Thanks for taking the time out of your day to read this.

Yep that is all possible and there are some examples in jme that do this already.

Check out TerrainFractalGridTest.java. It generates the terrain “randomly” (ie each tile will be different, but if you re-generated it each tile will be as it was the last time since it used the same seed value). It also uses the HeightBasedTerrain.j3md material that textures based on the height of the terrain.

Hope that helps.

1 Like

Hey,

Thanks for the fast reply! I checked out TerrainFractalGridTest, and from what hear this is going to be perfect. However, for some reason I was not able to get it to work, I copied and pasted the Code exactly, and for some reason, when the Window comes up the background is blue but there is no terrain, I checked to see if I had messed up, but I didn’t. I don’t know why but when I got in it didn’t generate the Terrain. Also I have a question, if it generates each tile randomly, how do the edges of the tile line up, I mean if each tile is random, wouldn’t there be some tearing? And also is there a way I can cap the size of the generation, say create a “Planet” but have it so that if a player reaches an edge he will the the tiles from what should be the far side of the map. Then it would give a feeling as if the map wraps around it self. I know this seems to be a very crude way to create a planet, but it is the style I want to go with.



Any advice is much appreciated.

That test takes a few moments for the terrain to load up, so you will see blue sky until then. And look down as you will be elevated a ways above the surface. You will also probably see logging code like this:

INFO: Child (Quad(1.0, 0.0, 2.0)Patch4) attached to this node (Quad(1.0, 0.0, 2.0))

That shows that it is loading. Moving around will cause new tiles to generate and more logging to appear. If you don’t see that, let me know.

Procedural generation of seamless tiles is easy enough if you know how :slight_smile:



(I imagine just googling the first 5 words of my first sentence would find plenty of examples!)

@Sploreg

I ran the program again, I didn’t see the Log for the Child (Quad…) There was nothing like that, There was a terrain attached to Root, if that helps. I did wait for about 3 minutes before I closed the Program, I now have no idea what happened.



@Zarch

Thanks, first 5 words were enough to find out what I was doing :D. You have any ideas for how to do the “Planet wrapping”?, I think I may use the Torus shape. But I am googleing around to see if anyone has made a planet shape before.

To map it onto a sphere?



You get a lot of choices on that. Google spherical texture mapping :slight_smile:

And you moved around? Make sure that the terrain grid has TerrainGridLodControl as its control, that will signal for tiles to be loaded.

I’ve just tried this on a couple of machines with the latest nightly and it appears to work fine.

Its all set up, I am pasting my code here. I got this right from the google code repo.



EDIT ALL THE IMPORTS HERE

[java]

public class TerrainFractalGridTest extends SimpleApplication {



private Material mat_terrain;

private TerrainGrid terrain;

private float grassScale = 64;

private float dirtScale = 16;

private float rockScale = 128;



public static void main(final String[] args) {

TerrainFractalGridTest app = new TerrainFractalGridTest();

app.start();

}

private CharacterControl player3;

private FractalSum base;

private PerturbFilter perturb;

private OptimizedErode therm;

private SmoothFilter smooth;

private IterativeFilter iterate;



@Override

public void simpleInitApp() {

this.flyCam.setMoveSpeed(100f);

ScreenshotAppState state = new ScreenshotAppState();

this.stateManager.attach(state);



// TERRAIN TEXTURE material

this.mat_terrain = new Material(this.assetManager, "Common/MatDefs/Terrain/HeightBasedTerrain.j3md");



// Parameters to material:

// regionXColorMap: X = 1…4 the texture that should be appliad to state X

// regionX: a Vector3f containing the following information:

// regionX.x: the start height of the region

// regionX.y: the end height of the region

// regionX.z: the texture scale for the region

// it might not be the most elegant way for storing these 3 values, but it packs the data nicely :slight_smile:

// slopeColorMap: the texture to be used for cliffs, and steep mountain sites

// slopeTileFactor: the texture scale for slopes

// terrainSize: the total size of the terrain (used for scaling the texture)

// GRASS texture

Texture grass = this.assetManager.loadTexture("Textures/Terrain/splat/grass.jpg");

grass.setWrap(WrapMode.Repeat);

this.mat_terrain.setTexture("region1ColorMap", grass);

this.mat_terrain.setVector3("region1", new Vector3f(15, 200, this.grassScale));



// DIRT texture

Texture dirt = this.assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg");

dirt.setWrap(WrapMode.Repeat);

this.mat_terrain.setTexture("region2ColorMap", dirt);

this.mat_terrain.setVector3("region2", new Vector3f(0, 20, this.dirtScale));



// ROCK texture

Texture rock = this.assetManager.loadTexture("Textures/Terrain/Rock2/rock.jpg");

rock.setWrap(WrapMode.Repeat);

this.mat_terrain.setTexture("region3ColorMap", rock);

this.mat_terrain.setVector3("region3", new Vector3f(198, 260, this.rockScale));



this.mat_terrain.setTexture("region4ColorMap", rock);

this.mat_terrain.setVector3("region4", new Vector3f(198, 260, this.rockScale));



this.mat_terrain.setTexture("slopeColorMap", rock);

this.mat_terrain.setFloat("slopeTileFactor", 32);



this.mat_terrain.setFloat("terrainSize", 513);



this.base = new FractalSum();

this.base.setRoughness(0.7f);

this.base.setFrequency(1.0f);

this.base.setAmplitude(1.0f);

this.base.setLacunarity(2.12f);

this.base.setOctaves(8);

this.base.setScale(0.02125f);

this.base.addModulator(new NoiseModulator() {



@Override

public float value(float… in) {

return ShaderUtils.clamp(in[0] * 0.5f + 0.5f, 0, 1);

}

});



FilteredBasis ground = new FilteredBasis(this.base);



this.perturb = new PerturbFilter();

this.perturb.setMagnitude(0.119f);



this.therm = new OptimizedErode();

this.therm.setRadius(5);

this.therm.setTalus(0.011f);



this.smooth = new SmoothFilter();

this.smooth.setRadius(1);

this.smooth.setEffect(0.7f);



this.iterate = new IterativeFilter();

this.iterate.addPreFilter(this.perturb);

this.iterate.addPostFilter(this.smooth);

this.iterate.setFilter(this.therm);

this.iterate.setIterations(1);



ground.addPreFilter(this.iterate);



this.terrain = new TerrainGrid("terrain", 33, 129, new FractalTileLoader(ground, 256f));



this.terrain.setMaterial(this.mat_terrain);

this.terrain.setLocalTranslation(0, 0, 0);

this.terrain.setLocalScale(2f, 1f, 2f);

this.rootNode.attachChild(this.terrain);



TerrainLodControl control = new TerrainLodControl(this.terrain, this.getCamera());

control.setLodCalculator(new DistanceLodCalculator(33, 2.7f)); // patch size, and a multiplier

this.terrain.addControl(control);







this.getCamera().setLocation(new Vector3f(0, 300, 0));



this.viewPort.setBackgroundColor(new ColorRGBA(0.7f, 0.8f, 1f, 1f));



}



@Override

public void simpleUpdate(final float tpf) {

}

}

[/java]

Yea you aren’t using the TerrainGridLodControl. That is why it isn’t showing up. (line 108 in the code you pasted)

Thanks, it works great now. Now I just need to play with the parameters to get what I want,

OK well, now after adjusting the parameters I have what I want. But I ran in to a problem, I need to add in a Dynamic Sky. However if I add a sky-dome, won’t the player eventually reach the edge of the sky-dome? How would I get around this? Also, if I have things like monsters roaming around the TerrainGrids, how would I attach the Monster to that TerrainGrid, so that when the player the Grid is not in the the Line of sight of that TerrainQuad, not only does the Quad get culled, but the Stuff on it also gets culled.

@acx234 said:
won't the player eventually reach the edge of the sky-dome?

Nope, that's the whole reason there is a SkyFactory class instead of just creating a normal sphere... if you set it up properly it's drawn so that its always in the background and your camera is always in the middle.

@acx234 said:
Also, if I have things like monsters roaming around the TerrainGrids, how would I attach the Monster to that TerrainGrid, so that when the player the Grid is not in the the Line of sight of that TerrainQuad, not only does the Quad get culled, but the Stuff on it also gets culled.


I think you're probably thinking too much in terms of grids here. You don't need the monsters to be walking around on the tile just because it's popped into view... or to wait until the whole tile is out of view before removing them either. If you're on one side of a tile the monster might be right on the other side of the tile hidden in fog and far out of sight. You just need to keep some sort of a list of the monsters and their positions in code and only add them to the scene as they come into your view range and remove them as they are no longer of interest. You can determine what that view range should be yourself, but it's usually going to be a lot less than the view range for the terrain because you might need to see the mountains in the distance but you don't need to see the monsters as little dots on the mountains from miles away, that's just a waste of power. Most of the time the monsters can exist just as a few numbers in an array keeping record of what they are and where they are and nothing more... you dont have to create them as fully fledged game objects and add them to the scene until they're just about to pop out of the fog.
You don't need to worry about removing things from the scene as you turn around on the spot etc, either as I understand it because the engine only draws what it needs to anyway... just worry about whether they're in the general area your player is or not and remove them from the scene and store them back as a bunch of numbers when they're no longer interesting.
1 Like
@acx234 said:
However if I add a sky-dome, won't the player eventually reach the edge of the sky-dome?


Skyboxes move with the player. It's not possible to "hit the end of the world" as far as the skybox is concerned. That's an entirely different story for your heightmap/ground though.
1 Like

So for adding things in and out of a the vision range of the player, I am thinking that I will use a Ghost Control to add and remove Monsters from the Physics Space as well as the Vision range for the Player. Am I going in the right Direction? (Also How would I so something like a Sniper Rifle? I am thinking I would just expand the Ghost Control by adding in like a rectangle in Viewing Direction.)



As for Storing them I created my own “Mob” object that extends Node, it has the mesh of the object, its Collision object, its Health. (As a side note, I tried added in Otto as an NPC that stands still, but for some reason I can walk through him, I have no Idea why.) Would I have some kind of massive array that would keep all the monsters, then on the update loop keep checking if the player’s Ghost Control can now see a Mob? This is the part that I am very confused with, because if I do that it will take forever to do a single frame.

Help please guys!

I was thinking about this a while ago, and hit upon the idea of sticking a GhostControl on each enemy, then using a custom control on the monster to check for whether the player had collided with the GhostControl. You’d then fire a ray from the monster to the player, and activate the monster based on the result of the ray (the distance between monster and player, and whether the monster has line-of-sight or not).



Have not tried it in the engine, though.

As with so many game related questions:


  1. Work smart not hard
  2. Look at what other people do for inspiration



    1:

    Don’t spawn ANY monsters until players can see them. Don’t simulate them either. As players approach the relevant area then spawn in the monsters either just out of sight (around a corner, in a cave, whatever) or with suitable animation (digging up out of the ground, teleporting, whatever).



    2.

    Generally games have “fixed” monsters that are always in a certain place. These are usually triggered by players entering a certain area and the encounter is fairly scripted.



    They also have “wandering” monsters that are spawned at random. Rules say what monsters are appropriate to each area and as players wander around you just roll the randoms and every now and then a monster (or herd of them) walks out from behind a tree/climbs out of the ground/flies down from the sky/is sitting behind that rock/whatever.