gpt4 book ai didi

javascript - JavaScript 中 map 平铺的平滑算法

转载 作者:行者123 更新时间:2023-12-03 03:57:42 25 4
gpt4 key购买 nike

我正在使用 JsIso(在 github 上找到它)来(希望)制作一个有趣的小浏览器游戏。我将高度图的硬编码值修改为变量和函数以随机生成地形。我想做但根本无法在脑海中想象的是,让给定的图 block 与其旁边的图 block 相差不超过或小于 2 层,消除塔和坑。

这是我当前的代码:

 var tileHeightMap = generateGround(10, 10); //Simple usage

function generateGround(height, width)
{
var ground = [];
for (var y = 0 ; y < height; y++)
{
ground[y] = [];
for (var x = 0; x < width; x++)
{
ground[y][x] = tile();
}
}
return ground;

function tile()
{
return (Math.random() * 5 | 0);
}
}

看起来最好修改图 block 函数,也许将前一个图 block 的值传递给它,而不是生成地面函数。如果需要更多信息,请告诉我!

最佳答案

您可以使用二维Value Noise .

它的工作原理基本上是这样的:

Octave #1:创建许多在 x 方向上均匀分布的随机点(例如 8 个)并在它们之间进行插值(如果您选择线性插值,则可能如下所示):

First step

Octave #2:执行与 #1 相同的操作,但点数加倍。幅度应为#1 中幅度的一半。现在再次插值并将两个 Octave 音阶的值相加。

Octave #3:执行与#2 中相同的操作,但使用双倍数量的点,并且幅度是#2 中幅度的一半。

只要您愿意,就可以继续执行这些步骤。

这会产生一维值噪声。以下代码生成 2d Value Noise 并将生成的 map 绘制到 Canvas 上:

function generateHeightMap (width, height, min, max) {

const heightMap = [], // 2d array containing the heights of the tiles
octaves = 4, // 4 octaves
startFrequencyX = 2,
startFrequencyY = 2;

// linear interpolation function, could also be cubic, trigonometric, ...
const interpolate = (a, b, t) => (b - a) * t + a;

let currentFrequencyX = startFrequencyX, // specifies how many points should be generated in this octave
currentFrequencyY = startFrequencyY,
currentAlpha = 1, // the amplitude
octave = 0,
x = 0,
y = 0;

// fill the height map with zeros
for (x = 0 ; x < width; x += 1) {
heightMap[x] = [];
for (y = 0; y < height; y += 1) {
heightMap[x][y] = 0;
}
}

// main loop
for (octave = 0; octave < octaves; octave += 1) {
if (octave > 0) {
currentFrequencyX *= 2; // double the amount of point
currentFrequencyY *= 2;
currentAlpha /= 2; // take the half of the amplitude
}

// create random points
const discretePoints = [];
for (x = 0; x < currentFrequencyX + 1; x += 1) {
discretePoints[x] = [];
for (y = 0; y < currentFrequencyY + 1; y += 1) {
// create a new random value between 0 and amplitude
discretePoints[x][y] = Math.random() * currentAlpha;
}
}

// now interpolate and add to the height map
for (x = 0; x < width; x += 1) {
for (y = 0; y < height; y += 1) {
const currentX = x / width * currentFrequencyX,
currentY = y / height * currentFrequencyY,
indexX = Math.floor(currentX),
indexY = Math.floor(currentY),

// interpolate between the 4 neighboring discrete points (2d interpolation)
w0 = interpolate(discretePoints[indexX][indexY], discretePoints[indexX + 1][indexY], currentX - indexX),
w1 = interpolate(discretePoints[indexX][indexY + 1], discretePoints[indexX + 1][indexY + 1], currentX - indexX);

// add the value to the height map
heightMap[x][y] += interpolate(w0, w1, currentY - indexY);
}
}
}

// normalize the height map
let currentMin = 2; // the highest possible value at the moment
for (x = 0; x < width; x += 1) {
for (y = 0; y < height; y += 1) {
if (heightMap[x][y] < currentMin) {
currentMin = heightMap[x][y];
}
}
}

// currentMin now contains the smallest value in the height map
for (x = 0; x < width; x += 1) {
for (y = 0; y < height; y += 1) {
heightMap[x][y] -= currentMin;
}
}

// now, the minimum value is guaranteed to be 0
let currentMax = 0;
for (x = 0; x < width; x += 1) {
for (y = 0; y < height; y += 1) {
if (heightMap[x][y] > currentMax) {
currentMax = heightMap[x][y];
}
}
}

// currentMax now contains the highest value in the height map
for (x = 0; x < width; x += 1) {
for (y = 0; y < height; y += 1) {
heightMap[x][y] /= currentMax;
}
}

// the values are now in a range from 0 to 1, modify them so that they are between min and max
for (x = 0; x < width; x += 1) {
for (y = 0; y < height; y += 1) {
heightMap[x][y] = heightMap[x][y] * (max - min) + min;
}
}


return heightMap;

}

const map = generateHeightMap(40, 40, 0, 2); // map size 40x40, min=0, max=2
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
for (let x = 0; x < 40; x += 1) {
for (let y = 0; y < 40; y += 1) {
const height = map[x][y];
ctx.fillStyle = 'rgb(' + height * 127 + ', 127, 127)';
// draw the tile (tile size 5x5)
ctx.fillRect(x * 5, y * 5, 5, 5);
}
}
<canvas width="200" height="200"></canvas>

请注意,此高度图中的值可以达到 -2 到 2。要更改它,请更改用于创建随机值的方法。

编辑:

我在那里犯了一个错误,编辑前的版本从-1到1。我修改了它,以便您可以轻松指定最小值和最大值。

首先,我对高度图进行标准化,使值真正达到从 0 到 1 的范围。然后,我修改所有值,使它们位于指定的最小值和最大值之间。

此外,我还更改了高度的显示方式。现在它显示出平滑的噪音,而不是陆地和水。一个点包含的红色越多,它就越高。

顺便说一句,该算法广泛应用于游戏的程序内容生成。

如果您需要进一步解释,请询问!

关于javascript - JavaScript 中 map 平铺的平滑算法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44862606/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com