文章首发及后续更新:https://mwhls.top/4489.html,无图/无目录/格式错误/更多相关请至首发页查看。
新的更新内容请到mwhls.top查看。
欢迎提出任何疑问及批评,非常感谢!
汇总:Unity 记录
摘要:柏林噪声生成 2D 地图,以二维数组表示。
参考:
Unity 中文手册 2021.1
Unity 2D-Extras
Mathf.PerlinNoise
目录
1. 粗糙的 1D 柏林噪声-2023/03/17
2. 陡峭可控的 1D 柏林噪声-2023/03/17
改进思路-2023/03/17
3. 1D 柏林噪声过渡区域-2023/03/17-2023/03/18
1. 粗糙的 1D 柏林噪声-2023/03/17
- 本来想一步到位,想想算了,脑子不够(拍了拍脑袋,发现空空的)。
- 实现方式
- 在取柏林噪声时,y 始终为 0,x 设为当前坐标即可。
- 效果如下
- 代码
int[,] generate_perlin1d(int width, int height, int base_x, int base_y){int[,] offset_array = new int[width, height];float[] perlin_array = new float[width];float perlin_h;for (int i = 0; i < width; i++){perlin_array[i] = Mathf.PerlinNoise(((i + base_x) + 0.5f), 0.5f);}for (int i = 0; i < width; i++){perlin_h = perlin_array[i] * height;for (int j = 0; j < height; j++){if (j < perlin_h){offset_array[i, j] = 1;}}}return offset_array;}
2. 陡峭可控的 1D 柏林噪声-2023/03/17
- 效果(从左到右,scale分别为 10, 5, 1)
- 代码
int[,] generate_perlin1d(int width, int height, int base_x, int base_y, float scale=10f){int[,] map_array = new int[width, height];float perlin_h;for (int i = 0; i < width; i++){perlin_h = height * Mathf.PerlinNoise(((i + base_x)/scale + 0.5f), 0.5f);for (int j = 0; j < height; j++){if (j < perlin_h){map_array[i, j] = 1;}}}return map_array;}
改进思路-2023/03/17
- 还好没有一步到位,做完之后发现做到这里就ok了。
- 原本还想弄个噪声变化区域的高度占比,这样可以只在顶部变化,而底部始终填充,但做完发现没必要,直接和其它的叠起来就好。
- 以及还有想弄陡峭程度的 scale,发现也没必要,越陡,整块面积也要越大,那直接把噪声的生成区域变大就好。
- 以及多个噪声堆叠,现在想想真是无意义,噪声的叠加还是噪声。
- 两个缺陷,不同 scale 与 y 时,区域不连续
- 即当生成区域的 y 值变化,对应的噪声区域也会上下移动。但这可以通过增加一块过渡区,逐渐减少 y 值来解决,如下图
- scale 的变化的话,感觉要计算一下原噪声位置,和新噪声位置,对齐才能实现。
- 但似乎也能用过渡区域来实现。
3. 1D 柏林噪声过渡区域-2023/03/17-2023/03/18
-
已知左区块高度及放缩,右区块高度及放缩,两区块间的 y 偏差,实现在两区块间加入过渡区域,让地图衔接平滑。
-
思路很简单,原来是一大块区域用同一个高度和同一个放缩,现在过渡区域细分,每个x对应一个高度和放缩,以及y偏差,用三个斜率实现就行。
- 和上面改进思路的图一样,上面只有 y 偏差,现在增加高度变化及放缩变化。
-
效果:
- 生成了四个区块,每个区块三个部分,左右两个正常地图,中间一个过渡地图,scale 从 10 5 间过渡,高度从 25 50 间过渡,偏差从 0 50 过渡
-
三区块生成代码
if (input_base.isKeydown("Fire3")){Vector3Int pos_tilemap = tilemap_modify.WorldToCell(input_base.get_mouse_pos(1));int[,] tmp_array = generate_perlin1d(tmp_w, tmp_h, pos_tilemap.x, pos_tilemap.y, scale:noise_scale);ArrayList pos_array = generate_pos_array(pos_tilemap, tmp_array);place_tile(tilemap_modify, pos_array, tile_place);
pos_tilemap.x += tmp_w;pos_tilemap.y += Mathf.Min(0, tmp_h2);tmp_array = generate_perlin1d_transition(tmp_w2, tmp_h2, tmp_h, noise_scale, tmp_h3, noise_scale2, pos_tilemap.x, pos_tilemap.y);pos_array = generate_pos_array(pos_tilemap, tmp_array);place_tile(tilemap_modify, pos_array, tile_place);pos_tilemap.x += tmp_w2;pos_tilemap.y += Mathf.Max(0, tmp_h2);tmp_array = generate_perlin1d(tmp_w3, tmp_h3, pos_tilemap.x, pos_tilemap.y, scale:noise_scale2);pos_array = generate_pos_array(pos_tilemap, tmp_array);place_tile(tilemap_modify, pos_array, tile_place);</code></pre>
- 过渡代码
int[,] generate_perlin1d_transition(int offset_x, int offset_y,int height_left, float scale_left, int height_right, float scale_right,int base_x, int base_y){int height, botton; if (offset_y >= 0){height = Mathf.Max(height_left, height_right + offset_y);botton = 0;} else{height = Mathf.Max(height_left - offset_y, height_right);botton = offset_y;}int[,] map_array = new int[offset_x, height];float perlin_i, height_i, scale_i, offset_y_i;float k_scale = (scale_right - scale_left) / (float)offset_x;float k_height = (height_right - height_left) / (float)offset_x;float k_offset_y = (float)offset_y / (float)offset_x;for (int i = 0; i < offset_x; i++){// alignment height, transit from height_left to height_rightheight_i = height_left + k_height * i; // perlin heightscale_i = scale_left + k_scale * i; // perlin scaleoffset_y_i = k_offset_y * i; // perlin offsetperlin_i = height_i * Mathf.PerlinNoise(((i + base_x)/scale_i + 0.5f), 0.5f); // perlin yfor (int j = 0; j < height; j++){if (j < perlin_i - botton + offset_y_i){map_array[i, j] = 1;}}
}return map_array; }</code></pre>