Again in the 4K arena, one of the effects I wanted to achieve in a game was a layered, cartoon-style terrain that I could use for different "depths" in earth or in a sea. Here are some screenshots of what I wanted to get, in a very tight bytecode:

(Screenshots from Gold Miner Vegas)
Now if you notice the terrain is exactly the same and the only thing that changes is the color scheme I wanted to go a bit further and generate the terrain randomly. Also notice that once you have this effect, you can apply it in many different situations : earth, sand dunes, oceans and seas, skies, etc.
The initial idea is pretty simple : we'll use a GeneralPath and construct a contour that is rectangular except for the top part, which we'll make curved:
After we have this outline, we fill it using an initial color. Then we repeat the procedure with a smaller contour on the already filled image, and continue until we reach the number of layers required. Each time, however, we decrease the brightness of the color with a fixed value. You should reach 0 by the time you get to the smallest contour:

How do we create the curved line? By using a path.quadTo() with a randomly modified control point. You can subdivide the width in equal steps, and just modify the control point height, or you can also alter the step randomly:

Equal intervals, control points in the middle and randomly modified height from the baseline
Here's the code snippet, finally :
Random rnd = new Random();
float baseH = 190/360f;
float baseS = 245/255f;
float baseB = 233/255f;
int MIN_Y =PLAYER_Y+PLAYER_SIZE;
int MAX_Y = SCR_HEIGHT;
int MIN_X = 0;
int MAX_X = WIDTH;
int LAYERS = 15;
float BRIGHTNESS_STEP=163/255f/LAYERS;
for (int y = MIN_Y; y<=MAX_Y; y+=(MAX_Y-MIN_Y)/LAYERS) {
g.setColor(Color.getHSBColor(baseH,baseS,baseB));
GeneralPath gp = new GeneralPath();
gp.moveTo(MIN_X,MAX_Y);
gp.lineTo(MIN_X,y);
int x = 0;
for (int i = 1; x < WIDTH; i++) {
int deltaY = rnd.nextInt(150)-75;
int deltaX = rnd.nextInt(200)+50;
gp.quadTo(x+deltaX/2,y+deltaY,x+deltaX,y);
x+=deltaX;
}
gp.lineTo(MAX_X,MAX_Y);
g.fill(gp);
g.setStroke(new BasicStroke(7));
g.setColor(Color.getHSBColor(baseH,baseS,baseB+BRIGHTNESS_STEP*3/2));
g.draw(gp);
baseB -= BRIGHTNESS_STEP;
}
In the above code, "g" is the Graphics2D context where you want your terrain to be drawn. You can play with the initial color and with the size of the random offsets. Here are some sample results:
![]() baseH = 10/360f; baseS = 175/255f; baseB = 163/255f; |
|
![]() float baseH = 190/360f; float baseS = 245/255f; float baseB = 200/255f; |
|