tilegame/src/heightmap.js

89 lines
2.1 KiB
JavaScript

import seedrandom from 'seedrandom'
class PerlinNoise {
constructor (rand = Math.random) {
let perm = new Int8Array(257)
for (let i = 0; i < 256; i++) {
perm[i] = i & 1 ? 1 : -1
}
for (let i = 0; i < 256; i++) {
let j = rand() * 4294967296 & 255
var _ref = [perm[j], perm[i]]
perm[i] = _ref[0]
perm[j] = _ref[1]
}
perm[256] = perm[0]
function noise1d (x) {
let x0 = x | 0
let x1 = x - x0
let xi = x0 & 255
let fx = (3 - 2 * x1) * x1 * x1
let a = x1 * perm[xi]
let b = (x1 - 1) * perm[xi + 1]
return a + fx * (b - a)
}
function noise (x) {
let sum = 0
sum += (1 + noise1d(x)) * 0.25
sum += (1 + noise1d(x * 2)) * 0.125
sum += (1 + noise1d(x * 4)) * 0.0625
sum += (1 + noise1d(x * 8)) * 0.03125
return sum
}
this.noise = noise
}
}
class HeightMap {
// amplitude - Controls the amount the height changes. The higher, the taller the hills.
// persistence - Controls details, value in [0,1]. Higher increases grain, lower increases smoothness.
// octaves - Number of noise layers
// period - Distance above which we start to see similarities. The higher, the longer "hills" will be on a terrain.
// lacunarity - Controls period change across octaves. 2 is usually a good value to address all detail levels.
constructor (offsetY, seed, amplitude = 30, persistence = 0.5, octaves = 5, period = 80, lacunarity = 2) {
this.iy = offsetY
this.seed = seed
this.noise = new PerlinNoise(seedrandom(seed))
this.amplitude = amplitude
this.period = period
this.lacunarity = lacunarity
this.octaves = octaves
this.persistence = persistence
}
getNoise (zx) {
let x = zx / this.period
let amp = 1.0
let max = 1.0
let sum = this.noise.noise(x)
let i = 0
while (++i < this.octaves) {
x *= this.lacunarity
amp *= this.persistence
max += amp
sum += this.noise.noise(x) * amp
}
return sum / max
}
getHeight (x) {
return this.getNoise(x) * this.amplitude + this.iy
}
}
export { HeightMap }