c#-地图生成器的渐变圆

因此,我正在制作一个可生成随机岛的地图生成器.它在生成器的心脏处使用Perlin噪声,然后在使用具有渐变的圆的方法来制作孤岛.

circle方法在地图的中心创建了多个圆形,其渐变从颜色开始(从64到0)渐变.问题在于,此方法在具有圆形边缘的地图部分上创建了非自然外观.当为一个像素生成Perlin噪声时,它将在渐变图上获得该像素,然后使其与蓝色值互斥.

因此,如果Perlin噪声在像素1、5上给出1,并且渐变图上的蓝色值为54,则将输出54的噪声值.如果在像素130、560上的Perlin噪声为0.5,且渐变颜色值为64那么噪声值为32.

这是我得到的:

该代码有两个关键点,佩林位:

noise = NoiseGenerator.Noise(x, y);
double gradColour = getGradColour(x, y).B;
double addedNoise = noise * gradColour;
double gradNoise = addedNoise;// - gradColour;

然后是渐变图生成器:

    public static void DrawGrad(float X, float Y, float R, Color C1, Color C2)
    {
        Graphics g = Graphics.FromImage(imgGrad);
        GraphicsPath path = new GraphicsPath();
        path.AddEllipse(X, Y, R, R);

        PathGradientBrush pathGrBrush = new PathGradientBrush(path);
        pathGrBrush.CenterColor = C1;

        Color[] colours = { C2 };
        pathGrBrush.SurroundColors = colours;
        g.FillEllipse(pathGrBrush, X, Y, R, R);
        //g.FillEllipse(Brushes.Red, X, Y, R, R);
        g.Flush();
    }

        int amount = rnd.Next(25, 30);
        for (int i = 0; i < amount / 4; i++)
        {
            float X = rnd.Next(-800, 1748);
            float Y = rnd.Next(-800, 1748);
            float R = rnd.Next(1000, 1200);
            DrawGrad(X, Y, R, Color.FromArgb(255, 0, 0, rnd.Next(15, 20)), Color.FromArgb(0, 0, 0, 0));
        }
        for (int i = 0; i < amount; i++)
        {
            double positionDiv = 1.98;
            double X1 = rnd.Next(0, 450) / positionDiv;
            double Y1 = rnd.Next(0, 450) / positionDiv;
            double R1 = rnd.Next(300, 650) / 4;
            float R = (float)R1;
            float X = (float)X1;
            float Y = (float)Y1;

            while (X + R > 1004)
            {
                X = 924 - R;
            }
            while (Y + R > 1004)
            {
                Y = 924 - R;
            }
            if(X < 30)
            {
                X = 30;
            }
            if(Y < 30)
            {
                Y = 30;
            }
            DrawGrad(X, Y, R, Color.FromArgb(255, 0, 0, rnd.Next(40, 64)), Color.FromArgb(0, 0, 0, rnd.Next(13, 17)));
        }

我只是想知道是否还有其他人知道C#中的其他方法可以使用perlin噪声创建孤岛?任何建议将不胜感激.

解决方法:

正如我在评论中提到的,菱形和正方形要容易得多,而且效果也足够好.所以算法:

>配置生成属性

在这里,您需要设置一组参数,例如最小,最大海拔,海平面,植被的海拔范围,沙子/岩石/污垢等,坡度参数等.
>创建地形高度图,我称之为zed [] []

为此,您需要稍微修改Diamond&Square算法.问题在于该算法会产生“内陆”地形.

要对其进行调整,以使其产生类似岛屿的地形,您需要使用尽可能低的拐角高度对其进行初始化.另外,您需要忽略第一步的钻石步骤,而是使用一些随机值(而不是角的平均值)来初始化中点.并且在每次平方迭代之后最后一次将边界点校正为最小(水下)标高(或其附近的某个随机值).

为了获得良好的输出,我使用大约范围< -2 ^ 15,2 ^ 16>.而一代.之后,我会在生成的地形中找到最小和最大海拔,然后重新缩放为配置的海拔范围.

不要忘了Diamond和square需要分辨率(2 ^ n)1的地图!
>创建表面贴图,我称之为typ [] []

地形图制作完成后,您可以按升序添加基于海拔的特征,例如:

>废物,沙子,植被类型,高山岩石,雪

然后根据地形坡度添加参数

>岩石

然后,您可以添加其他内容,例如(基于某些规则):

>河流,溪流,瀑布,建筑,道路,…

我在C中这样做:

void map_random(int _xs,int _ys)
    {
    // config
    int h0=-1000,h1=3000;       // [m] terrain elevation range
    int h_water= 0;             // [m] sea level
    int h_sand=15;              // [m] sand level
    int h_evergreen=1500;       // [m] evergreen level
    int h_snow=2000;            // [m] snow level
    int h_rock=1800;            // [m] mountine rock level
    float a_rock=60.0;          // [deg] mountine rock slope
    float d_pixel=15.0;         // [m] pixel size
    bool _island=true;

    // types
    enum _cover_enum
        {
        _cover_none=0,
        _cover_water,
        _cover_snow,
        _covers,
        _cover_shift=0,
        _cover_mask=15,
        };
    DWORD _cover[_covers]=
        {
        //  RRGGBB
        0x00000000,     // none
        0x00004080,     // water
        0x008F8F8F,     // snow
        };
    enum _terrain_enum
        {
        _terrain_enum_beg=-1,
        _terrain_dirt,
        _terrain_sand,
        _terrain_rock,
        _terrains,
        _terrain_shift=4,
        _terrain_mask=15,
        };
    DWORD _terrain[_terrains]=
        {
        //  RRGGBB
        0x00301510,     // dirt
        0x00EEC49A,     // sand
        0x00777777,     // rock
        };
    enum _flora_enum
        {
        _flora_enum_beg=-1,
        _flora_none,
        _flora_grass,
        _flora_hardwood,
        _flora_evergreen,
        _flora_deadwood,
        _floras,
        _flora_shift=8,
        _flora_mask=15,
        };
    DWORD _flora[_floras]=
        {
        //  RRGGBB
        0x00000000,     // none
        0x007F7F3F,     // grass
        0x001FFF1F,     // hardwood
        0x00007F00,     // evergreen
        0x007F3F1F,     // deadwood
        };

    // variables
    float a,b; int c,t,f;
    int x,y,z,xx,yy,mxs,mys,dx,dy,dx2,dy2,r,r2;
    int **ter=NULL,**typ=NULL;
    Randomize();
    // align resolution to power of 2
    for (mxs=1;mxs+1<_xs;mxs<<=1); if (mxs<3) mxs=3;
    for (mys=1;mys+1<_ys;mys<<=1); if (mys<3) mys=3;
    ter=new int*[mys+1]; for (y=0;y<=mys;y++) ter[y]=new int[mxs+1];
    typ=new int*[mys+1]; for (y=0;y<=mys;y++) typ[y]=new int[mxs+1];

    // [Terrain]

    // diamond & square random height map -> ter[][]
    dx=mxs; dx2=dx>>1; r=1<<16;                     // init step,half step and randomness
    dy=mys; dy2=dy>>1; r2=r>>1;
    // set corners values
    if (_island)
        {
        t=-r2;
        ter[  0][  0]=t;
        ter[  0][mxs]=t;
        ter[mys][  0]=t;
        ter[mys][mxs]=t;
        ter[dy2][dx2]=r2;
        }
    else{
        ter[  0][  0]=Random(r);
        ter[  0][mxs]=Random(r);
        ter[mys][  0]=Random(r);
        ter[mys][mxs]=Random(r);
        }
    for (;dx2|dy2;dx=dx2,dx2>>=1,dy=dy2,dy2>>=1)    // subdivide step until full image is filled
        {
        if (!dx) dx=1;
        if (!dy) dy=1;
        // diamond (skip first one for islands)
        if ((!_island)||(dx!=mxs))
         for (y=dy2,yy=mys-dy2;y<=yy;y+=dy)
          for (x=dx2,xx=mxs-dx2;x<=xx;x+=dx)
           ter[y][x]=((ter[y-dy2][x-dx2]+ter[y-dy2][x+dx2]+ter[y+dy2][x-dx2]+ter[y+dy2][x+dx2])>>2)+Random(r)-r2;
        // square
        for (y=dy2,yy=mys-dy2;y<=yy;y+=dy)
         for (x=dx ,xx=mxs-dx ;x<=xx;x+=dx)
          ter[y][x]=((ter[y][x-dx2]+ter[y][x+dx2]+ter[y-dy2][x]+ter[y+dy2][x])>>2)+Random(r)-r2;
        for (y=dy ,yy=mys-dy ;y<=yy;y+=dy)
         for (x=dx2,xx=mxs-dx2;x<=xx;x+=dx)
          ter[y][x]=((ter[y][x-dx2]+ter[y][x+dx2]+ter[y-dy2][x]+ter[y+dy2][x])>>2)+Random(r)-r2;
        for (x=dx2,xx=mxs-dx2;x<=xx;x+=dx)
            {
            y=  0; ter[y][x]=((ter[y][x-dx2]+ter[y][x+dx2]+ter[y+dy2][x])/3)+Random(r)-r2;
            y=mys; ter[y][x]=((ter[y][x-dx2]+ter[y][x+dx2]+ter[y-dy2][x])/3)+Random(r)-r2;
            }
        for (y=dy2,yy=mys-dy2;y<=yy;y+=dy)
            {
            x=  0; ter[y][x]=((ter[y][x+dx2]+ter[y-dy2][x]+ter[y+dy2][x])/3)+Random(r)-r2;
            x=mxs; ter[y][x]=((ter[y][x-dx2]+ter[y-dy2][x]+ter[y+dy2][x])/3)+Random(r)-r2;
            }

        // adjust border
        if (_island)
            {
            for (y=0;y<=mys;y+=dy2) { ter[y][0]=t; ter[y][mxs]=t; }
            for (x=0;x<=mxs;x+=dx2) { ter[0][x]=t; ter[mys][x]=t; }
            }

        // adjust randomness
        // r=(r*100)>>8; if (r<2) r=2; r2=r>>1;
        r>>=1; if (r<2) r=2; r2=r>>1;
        }
    // rescale to <h0,h1>
    xx=ter[0][0]; yy=xx;
    for (y=0;y<mys;y++)
     for (x=0;x<mxs;x++)
        {
        z=ter[y][x];
        if (xx>z) xx=z;
        if (yy<z) yy=z;
        }
    for (y=0;y<mys;y++)
     for (x=0;x<mxs;x++)
      ter[y][x]=h0+(((ter[y][x]-xx)*(h1-h0))/(yy-xx));

    // [Surface]

    for (y=0;y<mys;y++)
     for (x=0;x<mxs;x++)
        {
        z=ter[y][x];
        // max slope [deg]
        a=atan2(ter[y][x+1]-z,d_pixel);
        b=atan2(ter[y+1][x]-z,d_pixel);
        if (a<b) a=b; a*=180.0/M_PI;

        c=_cover_none;
        if (z<=h_water) c=_cover_water;
        if (z>=h_snow ) c=_cover_snow;

        t=_terrain_dirt;
        if (z<=h_sand)  t=_terrain_sand;
        if (z>=h_rock)  t=_terrain_rock;
        if (a>=a_rock)  t=_terrain_rock;

        f=_flora_none;
        if (t==_terrain_dirt)
            {
            r=Random(100);
            if (r>10) f=_flora_grass;
            if (r>50)
                {
                if (z>h_evergreen) f=_flora_evergreen;
                else{
                    r=Random(h_evergreen);
                    if (r<=z) f=_flora_evergreen;
                    else      f=_flora_hardwood;
                    }
                }
            if (r<5) f=_flora_deadwood;
            }
        typ[y][x]=(c<<_cover_shift)|(t<<_terrain_shift)|(f<<_flora_shift);
        }

    // [copy data] rewrite this part to suite your needs it just compute color based on type of terrain and height
    // ter[][] is elevation in meters
    // typ[][] is surface type
/*
    for (y=0;y<_ys;y++)
     for (x=0;x<_xs;x++)
       pic.p[y][x].dd=(((ter[y][x]-h0)*255)/(h1-h0))*0x00010101;
    for (y=0;y<_ys;y++)
     for (x=0;x<_xs;x++)
        {
        r=typ[y][x];
        c=(r>>  _cover_shift)&  _cover_mask;
        t=(r>>_terrain_shift)&_terrain_mask;
        f=(r>>  _flora_shift)&  _flora_mask;
               r=_terrain[t];
        if (c) r=  _cover[c];
        if (c==_cover_water)
            {
            xx=256-((ter[y][x]<<7)/h0);
            yy=int(r>>16)&255; yy=(yy*xx)>>8; r=(r&0x0000FFFF)|(yy<<16);
            yy=int(r>> 8)&255; yy=(yy*xx)>>8; r=(r&0x00FF00FF)|(yy<< 8);
            yy=int(r    )&255; yy=(yy*xx)>>8; r=(r&0x00FFFF00)|(yy    );
            }
        if (f){ if (c) r|=_flora[f]; else r=_flora[f]; };
        pic.p[y][x+_xs].dd=r;
        }
*/    
    // free ter[][],typ[][]
    for (y=0;y<=mys;y++) delete[] ter[y]; delete[] ter; ter=NULL;
    for (y=0;y<=mys;y++) delete[] typ[y]; delete[] typ; typ=NULL;
    }

当前设置的输出如下所示:

c#-地图生成器的渐变圆

[笔记]

这种方法通常在岛上只产生一个大山丘. (生成内陆就可以了)如果需要更多的地形,可以创建更多的地形图并将其平均.

我改为执行以下操作:我将中间点设置为最大高度,而忽略了第一次钻石通过.在第一个正方形通过之后,我将中点设置回一些随机值.这增加了更多的*山丘的可能性,而不仅仅是一个.使用这种方法并添加照明(环境正常阴影)以预览和略微调整像素大小(35m),我得到了以下结果:

c#-地图生成器的渐变圆

在极少数情况下,这会生成内陆图(如果中心区域太小.要处理它,您可以扫描角点以寻找破损.如果有土地,则再次生成,或者在第一遍中增加中心点随机性的偏差.

您可以使用代码,例如添加河流:

>寻找最高的山丘
>随机获得靠近/靠近它的位置
>将其设置为河流类型
>查找未设置为河流类型的最小高度相邻像素
>如果它在地图边缘或设置为海/水类型,则停止,否则循环#3

如果您想要更多条河流,那么不要忘了对已经完成的河流使用某种临时类型,以便算法可以正常工作.您还可以从起点开始增加河流的流量…结果如下:

c#-地图生成器的渐变圆

此后,您还应该均衡形成的湖泊水位.

上一篇:java-是否存在有关如何使用Expect4j库的真实文档或代码示例?


下一篇:如何在nuke表达式中给python函数提供参数?