UNPKG

phaser

Version:

A fast, free and fun HTML5 Game Framework for Desktop and Mobile web browsers from the team at Phaser Studio Inc.

201 lines (185 loc) 5.89 kB
var Hash = require('./Hash'); /** * Hash a number or list of numbers to a cellular noise value. * * A hash is an unpredictable transformation of an input, * which always returns the same output from the same input. * It is useful for generating random data in a predictable way. * * Cellular noise uses hashes to distort a grid, creating distinctive 'cells' * in a continuous pattern. While the result is still effectively random, * it is continuous: very similar inputs produce very similar outputs * (although there may be some minor discontinuities between cells). * The result has a distinctive bumpy pattern. * This is the algorithm used in the NoiseCell2D family of GameObjects. * It is sometimes called Worley or Voronoi noise. * * For example, you could use cellular noise to create a series of ridges * across a procedural terrain. Every time you generate the same region, * it will look the same. * * This function takes 1-4 numbers as input, and returns a single number. * The range of the return number increases with the number of inputs. * It is the distance from the input vector to the nearest distorted cell * center. In higher dimensions, the possible distance is higher. * * Note: If you specify dimensional properties in the config parameter, * ensure they are at least as long as the input vector. * Missing values can corrupt the result. * * Disclaimer: This function is intended for efficiently generating visual * variety. It is not intended for cryptographic use. Do not use it for * security/authentication/encryption purposes. Use a proper tool instead. * * Performance note: A 16ms frame has enough time to generate * a few hundred hash values, depending on device and workload. * * See {@link Phaser.Math.Hash} for more information on the hashing algorithms. * * @function Phaser.Math.HashCell * @since 4.0.0 * * @param {number|number[]} vector - The input vector to hash. 1 to 4 numbers. * @param {Phaser.Types.Math.HashCellConfig} [config] - The configuration of the noise cell field. * * @return {number} The hashed cellular noise value. The range increases with the number of input dimensions, as it represents the distance to the nearest distorted cell center. */ var HashCell = function (vector, config) { if (typeof vector === 'number') { vector = [ vector ]; } if (!config) { config = {}; } var value = 0; var iterations = config.noiseIterations || 1; for (var iteration = 0; iteration < iterations; iteration++) { var scale = Math.pow(2, iteration); value += (worley(vector, config, scale) - 0.5) / scale; } return value + 0.5; }; var defaultSeed = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 ]; var point = Array(4); var frac = Array(4); var neighbor = Array(4); var cell = Array(4); var jit = Array(4); var diff = Array(4); var worley = function (vector, config, scale) { var i, jit, d, index; var mode = config.noiseMode || 0; var smoothing = config.noiseSmoothing === undefined ? 1 : config.noiseSmoothing; // Normalize vector to unit grid. var axes = Math.max(1, Math.min(vector.length, 4)); var cells = config.noiseCells || [ 32, 32, 32, 32 ].slice(0, axes); for (i = 0; i < axes; i++) { var c = vector[i] * scale * cells[i]; point[i] = Math.floor(c); frac[i] = c % 1; } var value = 0; var random = 0; if (mode === 0 || mode === 1) { value = 4 * axes; } var neighbors = Math.pow(3, axes); for (index = 0; index < neighbors; index++) { // Generate neighbourhood in range -1,1 on relevant axes. neighbor[0] = index % 3 - 1; if (axes > 1) { neighbor[1] = Math.floor(index / 3) % 3 - 1; if (axes > 2) { neighbor[2] = Math.floor(index / 9) % 3 - 1; if (axes > 3) { neighbor[3] = Math.floor(index / 27) % 3 - 1; } } } jit = jitter( axes, point, neighbor, config, scale ); d = distSquared( axes, neighbor, frac, jit ); switch (mode) { case 0: { if (d < value) { value = d; } break; } case 1: { if (d < value) { value = d; random = jit[0]; } break; } case 2: { d = Math.sqrt(d); value += Math.pow(2, -32 / smoothing * d); break; } } } if (mode === 0) { return Math.sqrt(value); } if (mode === 1) { return random; } return -(1 / 32 * smoothing) * Math.log2(value); }; var jitter = function (axes, point, neighbor, config, scale) { var i, j; var wrap = config.noiseWrap ? config.noiseWrap : config.noiseCells || [ 32, 32, 32, 32 ]; var seed = config.noiseSeed ? config.noiseSeed : defaultSeed; for (i = 0; i < axes; i++) { cell[i] = (point[i] + neighbor[i]) % (wrap[i] * scale); } for (i = 0; i < axes; i++) { var vec = Array(axes); for (j = 0; j < axes; j++) { vec[j] = cell[j] + seed[i * axes + j]; } jit[i] = Hash(vec, config.algorithm); } return jit; }; var distSquared = function (axes, neighbor, frac, jitter) { var i; for (i = 0; i < axes; i++) { diff[i] = neighbor[i] - frac[i] + jitter[i]; } var d = 0; for (i = 0; i < axes; i++) { d += diff[i] * diff[i]; } return d; }; module.exports = HashCell;