我目前正在为我的游戏制作某种地图生成算法。我对我希望它做什么以及如何生成地图有基本的了解。
我想使用Polar Coordinate系统。我想要一个圆形图形,这样每个玩家都会在圆圈的边缘产生,均匀地展开。
该算法应生成从整个圆圈(但仅在圆圈内)展开的“城市”。每个城市都应该以某种方式联系起来。
圆圈的大小应取决于玩家的数量。
一切都应该是随机的,这意味着如果我跑
GenerateMap()
两次,它不应该给出相同的结果。
这是一张显示我想要的照片:img
红色箭头指向城市,线条是城市之间的连接。
我如何根据上述内容创建算法?
更新:抱歉,链接已损坏。修正了它。
答案 0 :(得分:1)
我看到这样的城市:
计算N
由于您的城市应具有恒定的平均密度,因此可以直接从中计算半径。因为它与平均或最小城市距离成线性比例。
N
(城市)次 (x,y)
(x,y)
在圈外 (x,y)
距离已经生成的城市太近的迭代 路径类似,只生成所有可能的路径(非随机)并扔掉:
在 C ++ 代码中,它可能如下所示:
//---------------------------------------------------------------------------
// some globals first
const int _max=128; // just max limit for cities and paths
const int R0=10; // city radius
const int RR=R0*R0*9; // min distance^2 between cities
int N=20; // number of cities
int R1=100; // map radius
struct _city { int x,y; }; // all the data you need for city
_city city[_max]; // list of cities
struct _path { int i0,i1; };// index of cities to join with path
_path path[_max]; // list of paths
int M=0; // number of paths in the list
//---------------------------------------------------------------------------
bool LinesIntersect(float X1,float Y1,float X2,float Y2,float X3,float Y3,float X4,float Y4)
{
if (fabs(X2-X3)+fabs(Y2-Y3)<1e-3) return false;
if (fabs(X1-X4)+fabs(Y1-Y4)<1e-3) return false;
float dx1,dy1,dx2,dy2;
dx1 = X2 - X1;
dy1 = Y2 - Y1;
dx2 = X4 - X3;
dy2 = Y4 - Y3;
float s,t,ax,ay,b;
ax=X1-X3;
ay=Y1-Y3;
b=(-(dx2*dy1)+(dx1*dy2)); if (fabs(b)>1e-3) b=1.0/b; else b=0.0;
s = (-(dy1*ax)+(dx1*ay))*b;
t = ( (dx2*ay)-(dy2*ax))*b;
if ((s>=0)&&(s<=1)&&(t>=0)&&(t<=1)) return true;
return false; // No collision
}
//---------------------------------------------------------------------------
// here generate n cities into circle at x0,y0
// compute R1,N from R0,RR,n
void genere(int x0,int y0,int n)
{
_city c;
_path p,*q;
int i,j,cnt,x,y,rr;
Randomize(); // init pseudo random generator
// [generate cities]
R1=(sqrt(RR*n)*8)/10;
rr=R1-R0; rr*=rr;
for (cnt=50*n,i=0;i<n;) // loop until all cities are generated
{
// watchdog
cnt--; if (cnt<=0) break;
// pseudo random position
c.x=Random(R1+R1)-R1; // <-r,+r>
c.y=Random(R1+R1)-R1; // <-r,+r>
// ignore cities outside R1 radius
if ((c.x*c.x)+(c.y*c.y)>rr) continue;
c.x+=x0; // position to center
c.y+=y0;
// ignore city if closer to any other then RR
for (j=0;j<i;j++)
{
x=c.x-city[j].x;
y=c.y-city[j].y;
if ((x*x)+(y*y)<=RR) { j=-1; break; }
}
if (j<0) continue;
// add new city to list
city[i]=c; i++;
}
N=i; // just in case watch dog kiks in
// [generate paths]
for (M=0,p.i0=0;p.i0<N;p.i0++)
for (p.i1=p.i0+1;p.i1<N;p.i1++)
{
// ignore too long path
x=city[p.i1].x-city[p.i0].x;
y=city[p.i1].y-city[p.i0].y;
if ((x*x)+(y*y)>5*RR) continue; // this constant determine the path density per city
// ignore intersecting path
for (q=path,i=0;i<M;i++,q++)
if ((q->i0!=p.i0)&&(q->i0!=p.i1)&&(q->i1!=p.i0)&&(q->i1!=p.i1))
if (LinesIntersect(
city[p.i0].x,city[p.i0].y,city[p.i1].x,city[p.i1].y,
city[q->i0].x,city[q->i0].y,city[q->i1].x,city[q->i1].y
)) { i=-1; break; }
if (i<0) continue;
// add path to list
if (M>=_max) break;
path[M]=p; M++;
}
}
//---------------------------------------------------------------------------
此处生成的布局概述:
N的增长:
蓝色圆圈是城市,灰色区域是目标圆圈,线条是路径。如果常量错误,cnt
只是看门狗以避免无限循环。正确设置_max
值,使其足够高N
或使用动态分配。路径比城市多得多,所以它们可以有单独的_max
值来保存记忆(太懒了,无法添加)。
您可以使用RandSeed
制作程序生成的地图......
您可以通过查找边界框并重新缩放到半径R1
来重新生成输出,以便在生成后更好地匹配圆形布局。
有些常量是凭经验获得的,所以要与它们一起玩,以达到最佳效果。