我想创建一个山上的地形,使用一个非常基本的原理,由这个高度映射显示:
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0 0 0
0 0 0 0 1 2 1 0 0 0 0
0 0 0 1 2 3 2 1 0 0 0
0 0 1 2 3 4 3 2 1 0 0
0 0 0 1 2 3 2 1 0 0 0
0 0 0 0 1 2 1 0 0 0 0
0 0 0 0 0 1 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
它从height = 4
随机点开始,然后逐渐减少邻居。
递归的想法很简单,我开始一点,用height - 1
(在这个例子中)递归到上/下/左/右,并且只有在没有遇到的情况下,我才设置它们的值。
我按如下方式实施:
private void createMountain(final float[][] heightMapping, final float startHeight) {
boolean[][] traversed = new boolean[width][depth];
boolean positive = (startHeight >= 0f);
int x = random.nextInt(width);
int z = random.nextInt(depth);
recursiveUpdate(heightMapping, traversed, x, z, startHeight, positive);
}
private void recursiveUpdate(final float[][] heightMapping, final boolean[][] traversed, final int x, final int z, final float startHeight, final boolean positive) {
if (x < 0 || x >= width || z < 0 || z >= depth) {
return;
}
if (traversed[x][z]) {
return;
}
if ((positive && startHeight <= 0f) || (!positive && startHeight >= 0f)) {
heightMapping[x][z] = 0f;
return;
}
traversed[x][z] = true;
heightMapping[x][z] = startHeight;
recursiveUpdate(heightMapping, traversed, x, z - 1, calculateNewStartHeight(startHeight, positive), positive);
recursiveUpdate(heightMapping, traversed, x, z + 1, calculateNewStartHeight(startHeight, positive), positive);
recursiveUpdate(heightMapping, traversed, x - 1, z, calculateNewStartHeight(startHeight, positive), positive);
recursiveUpdate(heightMapping, traversed, x + 1, z, calculateNewStartHeight(startHeight, positive), positive);
}
private float calculateNewStartHeight(final float startHeight, final boolean positive) {
float delta = startHeight / maxDecayFactor;
return (positive) ? startHeight - delta : startHeight + delta;
}
然而,它给了我以下输出:
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.1
1.9 1.6 1.2 1.0 0.8 0.6 0.5 0.4 0.3 0.3 0.2 0.2 0.1 0.1 0.1 0.1
2.4 3.0 3.8 4.7 5.9 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.1
问题是它现在形成一条线,这不是我的意图,而不是逐渐平滑。
如何实现我想要的算法?
答案 0 :(得分:3)
你的递归方法的问题在于它基本上执行DFS,因此你总是朝着一个方向前进,跟随最长的分支。但这个分支总是腐朽。
因为你也在维护一个traversed
集 - 它错误地确保你以后不会为另一个分支(另一个递归调用)访问同一个顶点。
有两种方法可以解决这个问题:
if (traversed[x][z]) { return; }
执行if (heightMapping[x][z] > startHeight) { return; }
之类的操作。如果它应该更高并且按预期工作,这将确保您可以更新高度。BFS更新应该类似于(伪代码):
Q <- new Queue() //or even better - priority queue that holds the highest point at the top
Q.push((x,y,height)
visited[width][depth]; //init as all false
while Q.empty() == false:
curr <- Q.pop()
if (sanity check for x<0 , y< 0 ,..):
continue
if visited[x][y] == true:
continue
if height <= 0: //or some epsilon instead of 0 if there are floating point issues
continue
heights[x][y] = height
visited[x][y] = true
Q.push(x+1,y,calculateNewHeight(...))
... //similarly for all directions
答案 1 :(得分:0)
不需要递归。
假设您希望山顶位于x,y位置的高度h。
height(x,y) = h
for dist = 1 to h-1
for x' = x - dist to x + dist
x_dist = abs(x - x')
y_dist = dist - x_dist
height(x', y + y_dist) = h - dist
height(x', y - y_dist) = h - dist
距离峰值的任何给定距离处的高度是山峰的高度,而不是与峰值的正交距离。我假设你从零开始,所以如果你离峰值足够远,那就不需要设置。