Hi !
Featured games (91)
games approved by the League of Dukes
Games in Showcase (808)
Games in Android Showcase (239)
games submitted by our members
Games in WIP (872)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  2D terrain maps (for side-scrollers): how to modulate strata with Perlin Noise  (Read 74287 times)
0 Members and 1 Guest are viewing this topic.
Offline philfrei
« Posted 2015-06-11 21:01:41 »

Ken Perlin writes about using his noise function to modulate or perturb a given color on slide 20 of his talk "Making Noise", e.g., making the color lighter or darker or varying its hue. When working on a 2D terrain map for a side-scroller, we can take this another step, and use the noise to modulate a strata set.

By strata, I am referring to a series of layers of various air and ground types. The basic layering function might be something like the following pseudo code function (for a board with a Y dimension of 24 blocks):

   getLayerType(int y) {
        if y < 4 then return layer1
        if y < 8 then return layer2
        if y < 12 then return layer3
        if y < 16 then return layer4
        if y < 20 then return layer5
        else return layer6

Note that here, the strata depend entirely on the Y value. The X value does not matter.

The way in which you assign layer types can be calculated either bottom or top or the reverse, and at any level of granularity. In the following graphic, the dims are 500 x 300, and the layering uses the following logic:

    blue > 240
    green > 180
    grey > 120
    brown > 60
    black > 0

The layers do not have to be of even thickness. For example, a thinner green layer might be a good way to suggest the ground's surface. The main point is that the basic layering, which you will use a starting point, should be something that is encapsulated in a function.

Now, you can modulate or perturb this function by adding a random component. Perlin Noise comes in various forms. I happen to like the Simplex Noise variant, but the "Improved Perlin Noise" is also a good choice. There are open source choices that can be found via search.

A 2D noise function usually takes the following form:
    noiseValue = getNoise( f(x), f(y) );

I use the notation f(x) and f(y) instead of (x, y) for two reasons:

(1) we want the noise value to relate to the position in the board array or the graphic. In this, I'm taking x to range from 0 to the width of the board array or graphic, and y to range from 0 to the height.

(2) the exact int values used for the [x, y] inevitably have to be modified to give a desired periodicity to the perturbations. The most common modification is a simple scaling function, e.g., f(x) = x * k, but more complex functions are possible, such as equations to suggest the illusion of perspective.

When iterating through the grid of the game screen, or through the pixels of the graphic, the function that returns the  layer type consists of your basic layer function, with the Y value being altered by the noise value. Following is a pseudo code example:

    for each y
        for each x
            noiseVal = noiseFunction(x * k, y * k);
            layerType = getLayerType( y + (noiseVal * modulationFactor) );

The sharpness of the contours depends on how you scale and proportion things. Noise functions typically return values ranging from -1 to 1. This has to be scaled by some factor in order to give a return value range that works for your desired level of smoothness (modulationFactor). Too little can be too flat or boring, too much can create sharp edges or lead to pockets of layers appearing out of sequence, e.g., a cave of air, or worse, clouds of green. Unfortunately, there's no guarantee that a good middle ground exists via this method. Sometimes to get an acceptable result, another iteration is needed (e.g., make a second pass where you impose a rule that for any vertically adjacent points, the delta Y is always positive and always less than a certain maximum).

In the above, the k value is used to convert the series of integers that identify pixel or grid location into a range that relates to the 'period' of the random curve lengths. If the noise function returns a maximum of one full wave curve per one unit (this is usually the case, or something close), and you want up to 2 waves per screen (where the screen is 50 units wide), then the scaling factor should be 2 / 50, or, k = 0.04. Similarly, if you wanted an average of 3 complete waves over the course of 500 pixels, the scaling factor would be 3 / 500, or k = 0.006. Note: the k value does not have to be the same for the X and Y directions.

In the following graphic, I modulated the strata function with a moderate amount of noise. I don't have the exact amount because the tool I used to generate the graphic only gives relatives value relating to its sliders. By eye-balling, I'm going to estimate that the modulationFactor gives us a variability approximately equal to the width of a single layer (60 pixels), So, it should be equal to 30 in this case, giving us +/-30 when multiplied against the [-1, 1] range of the noise function output.

I hope the above explanation helps you to understand better understand how to use Perlin noise, and the concept of how to calculate the factors needed to scale both the periodicity and the strength of the noisiness.

One other note: you aren't restricted to making a single call to Perlin noise. Often, periodicities are combined by making multiple Noise function calls, each with a different K, with the results combined at various proportions. This technique too much to cover in this tutorial, but you can read Ken Perlin's description of a fractal example at the following location, slide 21 of his "Making Noise" presentation.

The diagrams were made with SiVi (Simplex Visualizer)

music and music apps:
Offline philfrei
« Reply #1 - Posted 2015-06-11 21:59:16 »

How does one edit a tutorial post?

music and music apps:
Offline Riven

« JGO Overlord »

Medals: 1371
Projects: 4
Exp: 16 years

Hand over your head.

« Reply #2 - Posted 2015-06-12 07:08:05 »

At the bottom of your pist you see the edit-icon.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings!
Pages: [1]
  ignore  |  Print  

mercenarius (7 views)
2020-06-04 19:26:01

mercenarius (11 views)
2020-06-04 19:13:43

Riven (851 views)
2019-09-04 15:33:17

hadezbladez (5838 views)
2018-11-16 13:46:03

hadezbladez (2637 views)
2018-11-16 13:41:33

hadezbladez (6255 views)
2018-11-16 13:35:35

hadezbladez (1505 views)
2018-11-16 13:32:03

EgonOlsen (4741 views)
2018-06-10 19:43:48

EgonOlsen (5800 views)
2018-06-10 19:43:44

EgonOlsen (3283 views)
2018-06-10 19:43:20
A NON-ideal modular configuration for Eclipse with JavaFX
by philfrei
2019-12-19 19:35:12

Java Gaming Resources
by philfrei
2019-05-14 16:15:13

Deployment and Packaging
by philfrei
2019-05-08 15:15:36

Deployment and Packaging
by philfrei
2019-05-08 15:13:34

Deployment and Packaging
by philfrei
2019-02-17 20:25:53

Deployment and Packaging
by mudlee
2018-08-22 18:09:50

Java Gaming Resources
by gouessej
2018-08-22 08:19:41

Deployment and Packaging
by gouessej
2018-08-22 08:04:08 is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!