3
\$\begingroup\$

I am developing a simple project using Java, for Android. It is a side-scroller with a procedurally generated, infinite world. Most of the generation will be working on underground but I expect the same principles would apply to features that would be above the ground.

I have 2 coordinates. X goes Left-Right and Y goes Up-Down. I have managed to generate a density map using Perlin. What I do is looping through X and Y values, putting them in a noise function, and evaluating the resulting float to decide whether to place a specific tile or not. I have successfully created a uniform tile distribution. However I need something a bit more specialized.

You see, in order to make this interesting, I need to place various resources (Coal, Iron, Silver, Gold) as well as monster spawns in the map. I am thinking that it would be more realistic to place different resources in different depth levels. So for example, I need coal to appear between Y = -20 and Y = -50, Iron between -40 and -100, ogre spawners between -40 and -300 etc.

However, if I set these boundaries with a simple if statement like:

if (y<-20 && y>-50) {
    // Generate coal
    noise = perlin.getnoise(x,y,7);
    if (noise>=threshold) map.put(x,y,TILE_TYPE_COAL);
}
if (y<-40 && y>-100) {
    // Generate iron
    noise = perlin.getnoise(x,y,7);
    if (noise>=threshold) map.put(x,y,TILE_TYPE_IRON);
}

This generates sharp edges between those boundaries, like this: https://i.sstatic.net/XJGLk.jpg

I need the noise to somehow generate resources that, when digging down, would gradually appear more often, and then gradually less so. Ease in and ease out.

For example, if I set the boundaries for coal to be between -20 and -50, most of the coal should appear in the middle of this ribbon, -35, while it should appear less in -20 and -50 levels. Perhaps I need a Gaussian distribution? I don't know where to start.

To put the question in a more mathematical form:

How do I manipulate the output of a Perlin noise function depending on one of the inputs (Y) in a non-abrupt, natural way, in order to gradually increase or decrease density for specific ranges of Y?

Thanks in advance

\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

A simple way to do this is to modify the threshold value based on the height.

if (noise>=threshold) map.put(x,y,TILE_TYPE_COAL);

This means that where threshold is small you'll be more likely to place coal, and where threshold is large, less likely to place it. So, you should be able to get a gradient in coal density by setting threshold as a function of y, in such a way that the threshold is high near the boundaries of the coal area, and low in the middle. Assuming your noise function outputs values from 0 to 1, you could try something like this:

ribbonDist = (y - ribbonCenter) / ribbonRadius;
threshold = 1.0 - coalOverallDensity * min(ribbonDist*ribbonDist, 1.0);

Here coalOverallDensity is a factor controlling how much coal there is overall, ribbonCenter is the y-value at the center of the ribbon (-35 in your example) and ribbonRadius is the distance from the center to the edge of the ribbon (15 in your example). You can see a graph of this function and adjust the parameters here.

I chose a quadratic function (ribbonDist*ribbonDist), but you could also use other options like a triangle function or a Gaussian to get a different look, if desired.

\$\endgroup\$
1
  • \$\begingroup\$ Thank you very much. This helped a lot. When I used this the way it is, it created a ribbon (with noisy gradient) but no gaps in between. I have added 2 parameters (one multiplies the result, the other is added) With all these variables, I can tweak the result as I see fit, and I was able to create something that was believable. Thank you \$\endgroup\$
    – Aykın
    Commented Jul 8, 2013 at 19:09

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .