地图生成器的渐变圆

所以我正在制作一个随机岛屿的地图生成器。 它在发生器的核心部分使用Perlin噪声,然后使用具有梯度的圆来形成岛。

圆方法在地图的中心创build了多个圆,渐变颜色从64开始到0。问题是,此方法正在创build具有圆形边的地图部分的非天生外观。 当一个像素产生珀林噪声时,它将在梯度图上得到该像素,然后用蓝色值对它进行多重比较。

因此,如果珀林噪声在像素1,5上给出一个,而在梯度图上的蓝色值是54,则它将输出54的噪声值。如果像素130,560上的珀林噪声为0.5,并且梯度颜色值为64那么噪声值为32。

这是我得到的:

我得到的图片

代码有两个关键点,即perlin位:

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噪声创build一个岛屿? 任何build议将不胜感激。

正如我在评论中所提到的,钻石和广场要容易得多。 所以algorithm:

  1. configuration生成属性

    在这里,您需要设置最小,最大海拔,海平面,植被高程范围,沙/岩石/土等参数,坡度参数等参数。

  2. 创build地形高度图我称之为zed[][]

    为此,您需要稍微修改菱形和方形algorithm。 问题是这个algorithm像地形一样产生“内陆”。

    要调整它,所以它产生像地形一样的岛屿,你需要用尽可能低的angular度来初始化它。 你也需要忽略第一个菱形步骤,用一些随机值来初始化中点(不是angular的平均值)。 最后,在每次平方迭代之后,将边界点修正为最小(水下)高程(或其附近的一些随机值)。

    为了实现良好的输出,我使用大约范围<-2^15 , 2^16>而生成。 在此之后,我可以在生成的地形中find最小和最大高程,并重新调整到configuration的高程范围。

    不要忘记,钻石和广场需要分辨率的地图(2^n)+1

  3. 创build表面贴图我称之为typ[][]

    当地形图完成后,您可以按照升序添加像这样的基于高程的特征:

    • watter,沙子,植被types,mountine岩石,雪

    然后添加基于地形坡度的参数

    • 岩石

    然后你可以添加其他的东西(根据一些规则):

    • 河stream,小溪,瓦尔特 – 瀑布,build筑,道路,…

我这样做在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; } 

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

例

[笔记]

这种做法通常只会在岛上产生一座大山。 (内部生成确定)如果您需要更多的地图,您可以创build更多的地形图并将它们平均。

我做了以下代替:我将中间点设置为最大高度,并忽略第一个钻石通行证。 在第一次方格过后,我把中间点设置回一些随机值。 这增加了更多的中心山然后只有一个的可能性。 使用这种方法,并添加照明(环境+正常阴影)预览和轻微调整像素大小( 35m ),我得到了这样的结果:

例

在极less数情况下,这可能会产生类似于内陆的地图(如果中心区域太小,处理它可以扫描angular落,如果有再次产生的地面,或者在第一阶段增加一些中心点随机性的偏差。

你可以玩代码例如添加河stream:

  1. find最凶猛的山头
  2. 得到随机位置closures/周围
  3. 将其设置为河streamtypes
  4. find未设置为河streamtypes的最小高度邻居像素
  5. 如果在地图的边缘,或者设置为海/水型,否则循环#3

    如果你想要多一条河stream,那么不要忘了对已经完成的河stream使用一些临时types,这样algorithm才能正常工作。 你也可以从开始的距离增加河stream量…这是结果:

    河流

    在此之后,您还应该平衡形成的湖泊水位。