一直很想做一个模拟现实世界的游戏,最近开始动手了!既然是一个世界那么地图自然是第一个要解决的问题,网上有很多生成地图的教程,但找不到一个完整的文章。经过几天的研究总结了一些问题。
第一步:散列函数
想在计算机中生成随机数并不容易,而且完全随机的数字对生成地图并没有什么帮助,最开始我想过使用无理数的小数部分来充当随机数列,但计算无理数是一个非常耗时的过程。拜读多位博主的博文后我找到一个不错的散列函数,其核心思想是使用移位、精度溢出来产生散列值。如下(java/c++通用)
int hash(int key) { key = ~key + (key << 15);key = key^(key >>> 12); key = key + (key << 2); key = key^(key >>> 4); key = key * 2057;key = key^(key >>> 16); return key;
}
然而生成高程时有x,y两个参数,当需要更多数据时需要更多参数,这时可以使用hash(x+hash(y))、hash(seed+hash(x+hash(y))这样的嵌套方式来获得散列值。nice!
第二步:生成基础地形
网上对于地形生成搜索出来的全是关于value噪声、柏林噪声来获得高程图,效果如下
(下面的图绿色为高度0.5以上的地块高度越高颜色越浅,蓝色为高度0.5以下的地块越低颜色越深)
虽然有了高低错落、零零散散的自然美感,但这显然无法称之为地图。
我需要使用一些其他的方法来使它在更大尺度上具有一定的结构,比如在图上选一个点,以此点为中心,在一定范围内距离越远高度越低,一言以蔽之就是画一个圆。如下
我们用第二张图片的高程为基础高程(要求:最大值为1权重2/3)第一张图片为辅助高程(要求:最大值为1权重1/3),重新生成图片:
还行吧?起码不那么单调了,岛峪的位置也不是一切随缘了,现在我们给图片添加多个圆:
注意这些圆有大有小,这表示他们的控制范围。还有,有些圆发生了变形、合并,因为图中有些点同时处于两个点的控制下,其高程将会被两个控制点叠加,我们要求基础高程的最大值为1,当发生叠加而没有溢出时我们不用理会,如果溢出,则直接把它赋值为1即可。接着我们以相同的权重重新合成地形:
地图的真实感瞬间起飞。
然而还是有些问题:
首先是控制点可能距离过近,有时甚至会合并成一个控制点。
其次是水陆比例不仅与选定的水平线有关还与控制点的大小、数量有关。
另外,控制点的作用范围不一定必需是圆,因为精确计算距离必须计算开方较耗费性能,如果使用平方距离则在转换成高程时会发生边缘等高线过于密集的问题,所以可以使用正方形作为作用范围的参考,生成某点高程时使用x轴y轴距离较大的一个选作此点到控制点的距离。效果如下,我感觉还是可以的没有想象中的那种对角线分布,肯定是不如圆形距离的。
要解决控制点距离过近的问题可以使用松弛算法进行处理,但注意不要过度松弛,否则会使控制点过度离散,进而导致"大陆"过度分离
水陆比例无法简单地通过地形生成解决。可以换一个角度,如果我们固定一个地图的水体的总量,水位的高度依据计算得出。则不论地形生成算法是什么样的都可以很好地控制水体面积。
当然,暂无实现,也不会有效果图了。先这样