Unity记录3.4-地图-柏林噪声生成 1D 地图及过渡地图

汇总:Unity 记录

摘要:柏林噪声生成 2D 地图,以二维数组表示。

参考:
Unity 中文手册 2021.1
Unity 2D-Extras
Mathf.PerlinNoise

1. 粗糙的 1D 柏林噪声-2023/03/17

  • 本来想一步到位,想想算了,脑子不够(拍了拍脑袋,发现空空的)。
  • 实现方式
    • 在取柏林噪声时,y 始终为 0,x 设为当前坐标即可。
  • 效果如下

Unity_011_PerlinNoise1d.png

  • 代码
    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)

Unity_012_ScaleChange.png

  • 代码
    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 值来解决,如下图
    • Unity_013_yChange.png
    • scale 的变化的话,感觉要计算一下原噪声位置,和新噪声位置,对齐才能实现。
    • 但似乎也能用过渡区域来实现。

3. 1D 柏林噪声过渡区域-2023/03/17-2023/03/18

  • 已知左区块高度及放缩,右区块高度及放缩,两区块间的 y 偏差,实现在两区块间加入过渡区域,让地图衔接平滑。

  • 思路很简单,原来是一大块区域用同一个高度和同一个放缩,现在过渡区域细分,每个x对应一个高度和放缩,以及y偏差,用三个斜率实现就行。

    • 和上面改进思路的图一样,上面只有 y 偏差,现在增加高度变化及放缩变化。
  • 效果:

    • 生成了四个区块,每个区块三个部分,左右两个正常地图,中间一个过渡地图,scale 从 10 5 间过渡,高度从 25 50 间过渡,偏差从 0 50 过渡
    • Unity_014_MapTransition.png
  • 三区块生成代码

        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;
    }

版权声明:
作者:MWHLS
链接:https://mwhls.top/4489.html
来源:无镣之涯
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
打赏
< <上一篇
下一篇>>