我们正在尝试使用钻石方形算法(Diamond-Square Algorithm)生成一个无界限的地图,但遇到了以下问题:
- 我们无法让噪声库正确工作。
- 纯 Python 实现速度太慢。
为此,我们想要知道是否可以以某种方式使钻石方形算法在技术上无界限。
2. 解决方法
回答一:
- 将地图划分为多个“图块”,然后将钻石方形算法应用到每个图块中。
- 每个图块必须足够大,以至于一个角落的高度不会对另一个角落的高度产生影响。
- 这样,就可以动态地创建和销毁图块,并将新出现的角落的高度设置为一个独立的随机值。
- 该值(以及图块中的随机性)必须根据图块的位置进行设置,以便每次生成相同的图块。
回答二:
- 最新版本的噪声模块(位于 http://pypi.python.org/pypi/noise/1.0b3)提到了它“修复了在 Windows 上使用 Visual C++ 编译时出现的问题”。
- 可以尝试使用此版本。将图块排列成一个 x,y 网格,并像 random.seed((x,y)) 这样为每个图块设置随机数生成器种子。
- 这样,每次返回同一块世界时,都会重新创建相同的 terrain。
- 使用钻石方形算法,每个图块的两边取决于相邻图块,但这种依赖关系不会一直传播到整个图块。
如果让每个图块依赖于它前面的图块(即上面和左边),然后编写一个 create_fake_tile 函数,假定所有前面的图块值都为 0,则会得到一个“坏的”图块,其中最右列和最底行是下一个图块依赖的正确值。
如果从屏幕前面的图块行和列开始绘制每个屏幕,那么世界中可见的部分将是正确的。
以下是代码示例:
import random
def midpoint_displacement(size):
"""
Generates a heightmap using the midpoint displacement algorithm.
Args:
size: The size of the heightmap to generate.
Returns:
A 2D array of heights.
"""
# Initialize the heightmap with random values.
heightmap = [[random.random() for _ in range(size)] for _ in range(size)]
# Apply the midpoint displacement algorithm.
for i in range(1, size - 1):
for j in range(1, size - 1):
# Calculate the midpoint of the current cell.
midpoint = (heightmap[i - 1][j - 1] + heightmap[i - 1][j + 1] +
heightmap[i + 1][j - 1] + heightmap[i + 1][j + 1]) / 4
# Displace the midpoint by a random amount.
midpoint += random.uniform(-1, 1)
# Set the height of the current cell to the midpoint.
heightmap[i][j] = midpoint
# Return the heightmap.
return heightmap
def create_tile(x, y, size):
"""
Creates a tile of the heightmap.
Args:
x: The x-coordinate of the tile.
y: The y-coordinate of the tile.
size: The size of the tile.
Returns:
A 2D array of heights.
"""
# Generate a heightmap using the midpoint displacement algorithm.
heightmap = midpoint_displacement(size)
# Set the height of the corners of the tile to 0.
heightmap[0][0] = 0
heightmap[0][size - 1] = 0
heightmap[size - 1][0] = 0
heightmap[size - 1][size - 1] = 0
# Return the heightmap.
return heightmap
def main():
# Create a 1024x1024 heightmap.
heightmap = [[0 for _ in range(1024)] for _ in range(1024)]
# Create tiles of the heightmap.
for i in range(0, 1024, 256):
for j in range(0, 1024, 256):
tile = create_tile(i, j, 256)
for x in range(256):
for y in range(256):
heightmap[i + x][j + y] = tile[x][y]
# Save the heightmap to a file.
with open('heightmap.txt', 'w') as f:
for row in heightmap:
for height in row:
f.write(str(height) + ' ')
f.write('\n')
if __name__ == "__main__":
main()