我正在使用JsIso(在github上找到它)(希望)制作一个有趣的小浏览器游戏。我将高度图的硬编码值修改为变量和函数以随机生成地形。我想做的事情,但根本无法想象,是给定的瓷砖不超过或低于其旁边瓷砖的2个等级,摆脱塔和坑。
这是我目前的代码:
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
看起来最好修改tile函数,也许传递前一个tile的值,而不是生成ground函数。如果需要更多信息,请告诉我们!
答案 0 :(得分:1)
您可以使用二维Value Noise。
它基本上是这样的:
Octave#1:创建一些随机点(例如8),它们在x方向上均匀分布并在它们之间进行插值(如果选择线性插值,它可能看起来像这样):
Octave#2:做与#1相同的事情,但是点数增加一倍。幅度应该是#1幅度的一半。现在再次插值并将两个八度音阶的值相加。
八度#3:做与#2相同的事情,但是有两倍的点数,幅度是#2中振幅的一半。
只要您愿意,请继续执行这些步骤。
这会创建一维的“价值噪音”。以下代码生成2d Value Noise并将生成的地图绘制到画布:
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.然后,我修改所有值,使它们在指定的最小值和最大值之间。
另外,我改变了高度的显示方式。它现在显示出平滑的噪音,而不是土地和水。点越红,它就越高。
顺便说一下,这种算法广泛用于游戏的程序内容生成。
如果您想进一步解释,请问!