Unity记录3.4-地图-柏林噪声生成 1D 地图及过渡地图
汇总:Unity 记录
摘要:柏林噪声生成 2D 地图,以二维数组表示。
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);
- 过渡代码
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_right
height_i = height_left + k_height * i; // perlin height
scale_i = scale_left + k_scale * i; // perlin scale
offset_y_i = k_offset_y * i; // perlin offset
perlin_i = height_i * Mathf.PerlinNoise(((i + base_x)/scale_i + 0.5f), 0.5f); // perlin y
for (int j = 0; j < height; j++){
if (j < perlin_i - botton + offset_y_i){
map_array[i, j] = 1;
}
}
}
return map_array;
}
共有 0 条评论