Your results are good because you have islands, continents, ponds and seas. The Perlin noise helps to generate a random, nonrandom character.
Basically, you reduce (mathematically) the infinite resolution of the noise function into a discrete set of two different fragments along with a very limited block resolution. Given that your result seems to be excellent.
Various things can improve your result. For example, lerp between your tile graphics:
// Exemplary p-code, fine-tuning required Color color_at (x, y) { Real u = x / width, v = y / height Real f = min (max(noise(u,v), 0), 1); Color c = water*f + hill*(1-f); return c; }
You can generalize your lerp function to any number of fragments.
Another possibility for sharp edges is based on Voronoi diagrams (1) . You have the same functions as above, but instead of interpolating you take the tile closest to the noise value:
Color color_at (x, y) { Real u = x / width, v = y / height Real f = min (max(noise(u,v), 0), 1); if (f<0.5) return water; else return hill; }
This is the same as yours, except that you do it pixel by pixel. Again, this can be generalized.
Once you have a good setup, you can use the noise for everything: the distribution of plants / trees, the spread of the enemy, animations (this will be the 1d-noise function), etc.
Change as your comment:
Adjacent 1d relief:
If you need a side view, as in a classic 2d jump and start, think about the 1d-noise function, iterate from 0 to the image width, take a noise function sample f at each stop, convert f to screen space, then each pixel above will be a part of the sky, each pixel below will be taken from your fragments:
for (int x=0; x!=width; ++x) { // Get noise value: f = noise1d (x/width); h = f * height + (height/2); // scale and center at screen-center // Select tile: Tile *tile; if (h < waterLimit) { h = waterLimit; tile = waterTile; } else { tile = terrainTile; } // Draw vertical line: for (int y=0; y<h; ++y) setPixel (x, y, skyColor(x,y)); for (int y=h; y<height; ++y) setPixel (x, y, tileColor(x,y, tile)); }
Again, an approximate pseudocode.
Full 2d levels in your current setup:
The noise function is very flexible. If you want less blue and greener, just omit the constant term, i.e. Instead of if(h < 0) -> blue
, do if(h < -0.25) -> blue
.
1: I have never tried this approach as I am involved in 3D rendering ( picogen.org )