极坐标图生成

时间:2016-11-14 23:54:30

标签: algorithm dictionary procedural-generation

我目前正在为我的游戏制作某种地图生成算法。我对我希望它做什么以及如何生成地图有基本的了解。

我想使用Polar Coordinate系统。我想要一个圆形图形,这样每个玩家都会在圆圈的边缘产生,均匀地展开。

该算法应生成从整个圆圈(但仅在圆圈内)展开的“城市”。每个城市都应该以某种方式联系起来。

圆圈的大小应取决于玩家的数量。

一切都应该是随机的,这意味着如果我跑

GenerateMap()

两次,它不应该给出相同的结果。

这是一张显示我想要的照片:img

红色箭头指向城市,线条是城市之间的连接。

我如何根据上述内容创建算法?

更新:抱歉,链接已损坏。修正了它。

1 个答案:

答案 0 :(得分:1)

我看到这样的城市:

  1. 计算N

    中的尺寸和常数

    由于您的城市应具有恒定的平均密度,因此可以直接从中计算半径。因为它与平均或最小城市距离成线性比例。

  2. 循环N(城市)次
  3. 生成具有统一分布的随机(x,y)
  4. 抛弃(x,y)在圈外
  5. 的迭代
  6. 抛弃(x,y)距离已经生成的城市太近的迭代
  7. 路径类似,只生成所有可能的路径(非随机)并扔掉:

    • 路径比城市之间的平均距离或最小距离长得多(连接最近的邻居)
    • 与已生成路径相交的路径

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

    此处生成的布局概述:

    overview

    N的增长:

    growth

    蓝色圆圈是城市,灰色区域是目标圆圈,线条是路径。如果常量错误,cnt只是看门狗以避免无限循环。正确设置_max值,使其足够高N或使用动态分配。路径比城市多得多,所以它们可以有单独的_max值来保存记忆(太懒了,无法添加)。

    您可以使用RandSeed制作程序生成的地图......

    您可以通过查找边界框并重新缩放到半径R1来重新生成输出,以便在生成后更好地匹配圆形布局。

    有些常量是凭经验获得的,所以要与它们一起玩,以达到最佳效果。