算法 – 如何在方格上创建分支脉/河状结构

前端之家收集整理的这篇文章主要介绍了算法 – 如何在方格上创建分支脉/河状结构前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我试图在程序上产生一些河流.

我有一个平面(没有高程概念)方格作为基础,并希望在其上绘制一个分支结构,如图所示.

你能分享一下可以用来完成的步骤吗?

我不是在寻找最快的实现,因为没有实时生成,但更简单的实现将是首选. Lua是我的语言,但任何事都可以.

更多的东西:

>形状应该是算法生成的.
>形状应该是
使用种子值可控制.

解决方法

我认为生成河流是一种落后的方法,因为你需要根据它们的形状调整很多东西,这将很难.我会创建随机地形高度图并从中提取特征(如在现实世界中),这更容易且更接近现实.在最终地图中,您忽略高度并使用平面高度(如果您真的想要平面地图).以下是您可以从高度图中提取的一些内容

>河流和湖泊

通过播种随机高海拔点并沿着它下坡到海平面或地图边缘.
>植被或地面

从坡度和高度,你可以确定地面是沙子,泥土,岩石.如果有树木,灌木丛,草地或其他什么.

在这里看看这个QA:random island generator

和一些河流概述:

调整地形生成的方式也会影响河流形状(无需仅生成岛屿).

种子也在为这种方法工作.

[Edit1]承诺C代码

这基本上生成随机高度图然后种子和下坡跟随河流(如果地形块下坡流动,湖泊会自动生成).地形类型也由坡度和高度确定.

  1. //---------------------------------------------------------------------------
  2. picture pic;
  3. //---------------------------------------------------------------------------
  4. void map_random(int _xs,int _ys)
  5. {
  6. // config
  7. int h0=-1000,h1=3000; // [m] terrain elevation range
  8. int h_water= 0; // [m] sea level
  9. int h_sand=15; // [m] sand level
  10. int h_evergreen=1500; // [m] evergreen level
  11. int h_snow=2000; // [m] snow level
  12. int h_rock=1800; // [m] mountine rock level
  13. float a_rock=60.0; // [deg] mountine rock slope
  14. float d_pixel=35.0; // [m] pixel size
  15. int d_river_w=5; // [pixel] river max width
  16. int d_river_l=150; // [pixel] river base length per width increase
  17. bool _island=true;
  18.  
  19. // types
  20. enum _cover_enum
  21. {
  22. _cover_none=0,_cover_water,// sea
  23. _cover_snow,_covers,_cover_shift=0,_cover_mask=15,};
  24. DWORD _cover[_covers]=
  25. {
  26. // RRGGBB
  27. 0x00000000,// none
  28. 0x00003080,// watter (sea)
  29. 0x00EEEEEE,// snow
  30. };
  31. enum _terrain_enum
  32. {
  33. _terrain_dirt=0,_terrain_sand,_terrain_rock,_terrain_water,// streams,rivers,lakes
  34. _terrain_temp,// temp
  35. _terrains,_terrain_shift=4,_terrain_mask=15,};
  36. DWORD _terrain[_terrains]=
  37. {
  38. // RRGGBB
  39. 0x00301510,// dirt
  40. 0x00EEC49A,// sand
  41. 0x006F6F6F,// rock
  42. 0x00006080,// water (streams,lakes)
  43. 0x00006080,// temp
  44. };
  45. enum _flora_enum
  46. {
  47. _flora_none=0,_flora_grass,_flora_hardwood,_flora_evergreen,_flora_deadwood,_floras,_flora_shift=8,_flora_mask=15,};
  48. DWORD _flora[_floras]=
  49. {
  50. // RRGGBB
  51. 0x00000000,// none
  52. 0x007F7F3F,// grass
  53. 0x001FFF1F,// hardwood
  54. 0x00007F00,// evergreen
  55. 0x007F3F1F,// deadwood
  56. };
  57.  
  58. // variables
  59. float a,b,da; int c,t,f;
  60. int x,y,z,xx,yy,mxs,mys,dx,dy,dx2,dy2,r,r2,ix,l;
  61. int xh1,yh1; // topest hill position
  62. int **ter=NULL,**typ=NULL;
  63. Randomize();
  64. // align resolution to power of 2
  65. for (mxs=1;mxs+1<_xs;mxs<<=1); if (mxs<3) mxs=3;
  66. for (mys=1;mys+1<_ys;mys<<=1); if (mys<3) mys=3;
  67. ter=new int*[mys+1]; for (y=0;y<=mys;y++) ter[y]=new int[mxs+1];
  68. typ=new int*[mys+1]; for (y=0;y<=mys;y++) typ[y]=new int[mxs+1];
  69.  
  70. // [Terrain]
  71. for (;;)
  72. {
  73. // diamond & square random height map -> ter[][]
  74. dx=mxs; dx2=dx>>1; r=(mxs+mys)<<1; // init step,half step and randomness
  75. dy=mys; dy2=dy>>1; r2=r>>1;
  76. // set corners values
  77. if (_island)
  78. {
  79. t=-r2;
  80. ter[ 0][ 0]=t;
  81. ter[ 0][mxs]=t;
  82. ter[mys][ 0]=t;
  83. ter[mys][mxs]=t;
  84. ter[dy2][dx2]=r+r; // top of central hill
  85. }
  86. else{
  87. ter[ 0][ 0]=Random(r);
  88. ter[ 0][mxs]=Random(r);
  89. ter[mys][ 0]=Random(r);
  90. ter[mys][mxs]=Random(r);
  91. }
  92. for (;dx2|dy2;dx=dx2,dx2>>=1,dy=dy2,dy2>>=1) // subdivide step until full image is filled
  93. {
  94. if (!dx) dx=1;
  95. if (!dy) dy=1;
  96. // diamond (skip first one for islands)
  97. if ((!_island)||(dx!=mxs))
  98. for (y=dy2,yy=mys-dy2;y<=yy;y+=dy)
  99. for (x=dx2,xx=mxs-dx2;x<=xx;x+=dx)
  100. 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;
  101. // square
  102. for (y=dy2,yy=mys-dy2;y<=yy;y+=dy)
  103. for (x=dx,xx=mxs-dx ;x<=xx;x+=dx)
  104. ter[y][x]=((ter[y][x-dx2]+ter[y][x+dx2]+ter[y-dy2][x]+ter[y+dy2][x])>>2)+Random(r)-r2;
  105. for (y=dy,yy=mys-dy ;y<=yy;y+=dy)
  106. for (x=dx2,xx=mxs-dx2;x<=xx;x+=dx)
  107. ter[y][x]=((ter[y][x-dx2]+ter[y][x+dx2]+ter[y-dy2][x]+ter[y+dy2][x])>>2)+Random(r)-r2;
  108. for (x=dx2,xx=mxs-dx2;x<=xx;x+=dx)
  109. {
  110. y= 0; ter[y][x]=((ter[y][x-dx2]+ter[y][x+dx2]+ter[y+dy2][x])/3)+Random(r)-r2;
  111. y=mys; ter[y][x]=((ter[y][x-dx2]+ter[y][x+dx2]+ter[y-dy2][x])/3)+Random(r)-r2;
  112. }
  113. for (y=dy2,yy=mys-dy2;y<=yy;y+=dy)
  114. {
  115. x= 0; ter[y][x]=((ter[y][x+dx2]+ter[y-dy2][x]+ter[y+dy2][x])/3)+Random(r)-r2;
  116. x=mxs; ter[y][x]=((ter[y][x-dx2]+ter[y-dy2][x]+ter[y+dy2][x])/3)+Random(r)-r2;
  117. }
  118. if (_island)
  119. {
  120. // recompute middle position after first pass so there can be more central hills
  121. if (dx==mxs) ter[dy2][dx2]=Random(r2);
  122. // adjust border to underwatter
  123. for (y=0;y<=mys;y+=dy2) { ter[y][0]=t; ter[y][mxs]=t; }
  124. for (x=0;x<=mxs;x+=dx2) { ter[0][x]=t; ter[mys][x]=t; }
  125. }
  126. // adjust randomness
  127. r>>=1; if (r<2) r=2; r2=r>>1;
  128. }
  129. // rescale to <h0,h1>
  130. xx=ter[0][0]; yy=xx;
  131. for (y=0;y<=mys;y++)
  132. for (x=0;x<=mxs;x++)
  133. {
  134. z=ter[y][x];
  135. if (xx>z) xx=z;
  136. if (yy<z){ yy=z; xh1=x; yh1=y; }
  137. }
  138. for (y=0;y<=mys;y++)
  139. for (x=0;x<=mxs;x++)
  140. ter[y][x]=h0+(((ter[y][x]-xx)*(h1-h0))/(yy-xx));
  141. // test for correctness
  142. if (_island)
  143. {
  144. l=0;
  145. for (x=0;x<=mxs;x++) { if (ter[0][x]>h_water) l++; if (ter[mys][x]>h_water) l++; }
  146. for (y=0;y<=mys;y++) { if (ter[y][0]>h_water) l++; if (ter[y][mxs]>h_water) l++; }
  147. if (l>1+((mxs+mys)>>3)) continue;
  148. }
  149. break;
  150. }
  151.  
  152. // [Surface]
  153. for (y=0;y<mys;y++)
  154. for (x=0;x<mxs;x++)
  155. {
  156. z=ter[y][x];
  157. // max slope [deg]
  158. a=atan2(ter[y][x+1]-z,d_pixel);
  159. b=atan2(ter[y+1][x]-z,d_pixel);
  160. if (a<b) a=b; a*=180.0/M_PI;
  161.  
  162. c=_cover_none;
  163. if (z<=h_water) c=_cover_water;
  164. if (z>=h_snow ) c=_cover_snow;
  165.  
  166. t=_terrain_dirt;
  167. if (z<=h_sand) t=_terrain_sand;
  168. if (z>=h_rock) t=_terrain_rock;
  169. if (a>=a_rock) t=_terrain_rock;
  170.  
  171. f=_flora_none;
  172. if (t==_terrain_dirt)
  173. {
  174. r=Random(100);
  175. if (r>10) f=_flora_grass;
  176. if (r>50)
  177. {
  178. if (z>h_evergreen) f=_flora_evergreen;
  179. else{
  180. r=Random(h_evergreen);
  181. if (r<=z) f=_flora_evergreen;
  182. else f=_flora_hardwood;
  183. }
  184. }
  185. if (r<5) f=_flora_deadwood;
  186. }
  187. typ[y][x]=(c<<_cover_shift)|(t<<_terrain_shift)|(f<<_flora_shift);
  188. }
  189.  
  190. // [Rivers]
  191. for (ix=10+Random(5),a=0.0,da=2.0*M_PI/float(ix);ix;ix--)
  192. {
  193. // random start around topest hill
  194. a+=da*(0.75+(0.50*Random()));
  195. for (l=0;l<10;l++)
  196. {
  197. b=Random(mxs>>3);
  198. x=xh1; x+=float(b*cos(a));
  199. y=yh1; y+=float(b*sin(a));
  200. if ((x<1)||(x>=mxs)) continue;
  201. if ((y<1)||(y>=mys)) continue;
  202. if (typ[y][x]&0x00F==_cover_water) continue;
  203. l=-1;
  204. break;
  205. } if (l>=0) continue; // safety check
  206. for (l=0,r2=0;;)
  207. {
  208. // stop on map edge
  209. if ((x<=0)||(x>=mxs-1)||(y<=0)||(y>=mys-1)) break;
  210. // decode generated surface
  211. r=typ[y][x];
  212. c=(r>> _cover_shift)& _cover_mask;
  213. t=(r>>_terrain_shift)&_terrain_mask;
  214. f=(r>> _flora_shift)& _flora_mask;
  215. // stop if reached sea
  216. if (c==_cover_water) break;
  217. // insert river dot radius = r2
  218. dx=x-r2; if (dx<0) dx=0; dx2=x+r2; if (dx2>=mxs) dx2=mxs-1;
  219. dy=y-r2; if (dy<0) dy=0; dy2=y+r2; if (dy2>=mys) dy2=mys-1;
  220. for (yy=dy;yy<=dy2;yy++)
  221. for (xx=dx;xx<=dx2;xx++)
  222. if (((xx-x)*(xx-x))+((yy-y)*(yy-y))<=r2*r2)
  223. if (((typ[yy][xx]>>_terrain_shift)&_terrain_mask)!=_terrain_water)
  224. typ[yy][xx]=(typ[yy][xx]&0x00F)|(_terrain_temp<<_terrain_shift);
  225. // step to smalest elevation neighbor
  226. dx=x; dy=y; z=h1; typ[y][x]=(typ[y][x]&0x00F)|(_terrain_water<<_terrain_shift); xx=x; yy=y;
  227. xx--; r=ter[yy][xx]; if ((z>=r)&&(((typ[yy][xx]>>_terrain_shift)&_terrain_mask)!=_terrain_water)) { z=r; dx=xx; dy=yy; }
  228. yy--; r=ter[yy][xx]; if ((z>=r)&&(((typ[yy][xx]>>_terrain_shift)&_terrain_mask)!=_terrain_water)) { z=r; dx=xx; dy=yy; }
  229. xx++; r=ter[yy][xx]; if ((z>=r)&&(((typ[yy][xx]>>_terrain_shift)&_terrain_mask)!=_terrain_water)) { z=r; dx=xx; dy=yy; }
  230. xx++; r=ter[yy][xx]; if ((z>=r)&&(((typ[yy][xx]>>_terrain_shift)&_terrain_mask)!=_terrain_water)) { z=r; dx=xx; dy=yy; }
  231. yy++; r=ter[yy][xx]; if ((z>=r)&&(((typ[yy][xx]>>_terrain_shift)&_terrain_mask)!=_terrain_water)) { z=r; dx=xx; dy=yy; }
  232. yy++; r=ter[yy][xx]; if ((z>=r)&&(((typ[yy][xx]>>_terrain_shift)&_terrain_mask)!=_terrain_water)) { z=r; dx=xx; dy=yy; }
  233. xx--; r=ter[yy][xx]; if ((z>=r)&&(((typ[yy][xx]>>_terrain_shift)&_terrain_mask)!=_terrain_water)) { z=r; dx=xx; dy=yy; }
  234. xx--; r=ter[yy][xx]; if ((z>=r)&&(((typ[yy][xx]>>_terrain_shift)&_terrain_mask)!=_terrain_water)) { z=r; dx=xx; dy=yy; }
  235. if ((dx==x)&&(dy==y))
  236. {
  237. // handle invalid path or need for a lake!!!
  238. if (dx>mxs>>1) dx++; else dx--;
  239. if (dy>mys>>1) dy++; else dy--;
  240. }
  241. x=dx; y=dy;
  242. // increase river volume with length
  243. l++; if (l>d_river_l*(r2+1)) { l=0; if (r2<d_river_w) r2++; }
  244. }
  245. // make merging of rivers possible
  246. for (y=0;y<=mys;y++)
  247. for (x=0;x<=mxs;x++)
  248. if (((typ[y][x]>>_terrain_shift)&_terrain_mask)==_terrain_water)
  249. typ[y][x]=(typ[y][x]&0x00F)|(_terrain_temp<<_terrain_shift);
  250. }
  251. for (y=0;y<=mys;y++)
  252. for (x=0;x<=mxs;x++)
  253. if (((typ[y][x]>>_terrain_shift)&_terrain_mask)==_terrain_temp)
  254. typ[y][x]=(typ[y][x]&0x00F)|(_terrain_water<<_terrain_shift);
  255.  
  256.  
  257. // [copy data] rewrite this part to suite your needs
  258. for (y=1;y<_ys;y++)
  259. for (x=1;x<_xs;x++)
  260. {
  261. float nx,ny,nz,x0,y0,z0,x1,y1,z1;
  262. // (nx,nz) = surface normal
  263. nx=0.0; ny=0.0; nz=ter[y][x];
  264. x0=-d_pixel; y0=0.0; z0=ter[y][x-1];
  265. x1=0.0; y1=-d_pixel; z1=ter[y-1][x];
  266. x0-=nx; x1-=nx;
  267. y0-=ny; y1-=ny;
  268. z0-=nz; z1-=nz;
  269. nx=(y0*z1)-(z0*y1);
  270. ny=(z0*x1)-(x0*z1);
  271. nz=(x0*y1)-(y0*x1);
  272. x0=1.0/sqrt((nx*nx)+(ny*ny)+(nz*nz));
  273. nx*=x0;
  274. ny*=x0;
  275. nz*=x0;
  276. // z = ambient light + normal shading
  277. nz=(+0.7*nx)+(-0.7*ny)+(+0.7*nz);
  278. if (nz<0.0) nz=0.0;
  279. nz=255.0*(0.2+(0.8*nz)); z=nz;
  280. // r = base color
  281. r=typ[y][x];
  282. c=(r>> _cover_shift)& _cover_mask;
  283. t=(r>>_terrain_shift)&_terrain_mask;
  284. f=(r>> _flora_shift)& _flora_mask;
  285. r=_terrain[t];
  286. if (c) r= _cover[c];
  287. if (f){ if (c) r|=_flora[f]; else r=_flora[f]; };
  288. // sea color is depending on depth not surface normal
  289. if (c==_cover_water) z=256-((ter[y][x]<<7)/h0);
  290. // apply lighting z to color r
  291. yy=int(r>>16)&255; yy=(yy*z)>>8; if (yy>255) yy=255; r=(r&0x0000FFFF)|(yy<<16);
  292. yy=int(r>> 8)&255; yy=(yy*z)>>8; if (yy>255) yy=255; r=(r&0x00FF00FF)|(yy<< 8);
  293. yy=int(r )&255; yy=(yy*z)>>8; if (yy>255) yy=255; r=(r&0x00FFFF00)|(yy );
  294. // set pixel to target image
  295. pic.p[y][x].dd=r;
  296. }
  297.  
  298. // free ter[][],typ[][]
  299. for (y=0;y<=mys;y++) delete[] ter[y]; delete[] ter; ter=NULL;
  300. for (y=0;y<=mys;y++) delete[] typ[y]; delete[] typ; typ=NULL;
  301. }
  302. //---------------------------------------------------------------------------

代码基于我所链接的答案中的代码,但具有附加功能(包括河流).我使用自己的图片图片,所以一些成员是:

> xs,ys图像大小(以像素为单位)
> p [y] [x] .dd是(x,y)位置的像素,为32位整数类型
>清晰(颜色) – 清除整个图像
> resize(xs,ys) – 将图像调整为新分辨率
> bmp – VCL封装了带Canvas访问的GDI Bitmap

您可以调整Diamond& Square中的调整随机性以更改地形平滑度.高度限制和阈值也可以被篡改.

为了实现像河流这样的更多的增长,在群集中种植更多的起始点,以便它们能够及时合并到单个或更多的河流中.

猜你在找的Lua相关文章