比中间点圆更好的算法用于iso网格上的瓦片地图画笔

时间:2016-07-13 22:28:27

标签: c# algorithm isometric

我正在研究这种iso网格游戏(更精确:二维投影,以典型的钻石布局编制索引),并希望实现圆形画笔在我的地图上绘制瓷砖,就像在任何图像编辑软件中一样。我从Midpoint Circle Algorithm开始,但立即注意到,结果并不像我想要的1到7之间的小画笔大小。

enter image description here

我更愿意这样的事情:

enter image description here

忽略,第一个圈子没有填满,当然这很容易。在iso网格上是否有适合的形状生成算法?我可能甚至不想要圆形,但是交替使用四边形和十字形/ x形。

以下是从维基百科中获取的第一张图片样本的代码:

static List<IntVector2> GetBrushCircleCoords(int x0, int y0, int radius)
{
    List<IntVector2> coords = new List<IntVector2>();
    int x = radius;
    int y = 0;
    int err = 0;

    while (x >= y)
    {
        coords.Add(new IntVector2(x0 + x, y0 + y));
        coords.Add(new IntVector2(x0 + y, y0 + x));
        coords.Add(new IntVector2(x0 - y, y0 + x));
        coords.Add(new IntVector2(x0 - x, y0 + y));
        coords.Add(new IntVector2(x0 - x, y0 - y));
        coords.Add(new IntVector2(x0 - y, y0 - x));
        coords.Add(new IntVector2(x0 + y, y0 - x));
        coords.Add(new IntVector2(x0 + x, y0 - y));

        y += 1;
        err += 1 + 2 * y;
        if (2 * (err - x) + 1 > 0)
        {
            x -= 1;
            err += 1 - 2 * x;
        }
    }
    return coords;
}

1 个答案:

答案 0 :(得分:5)

您没有指定等轴网格的布局。我假设钻石,因为它更容易在那里实施。但是在整数算术中很难实现半径的半单元分辨率。对于完整细胞分辨率半径圆盘填充使用简单的2嵌套for s与内圈测试。结果如下:

raw

只需忽略我的Isometric编辑器的树和图块列表叠加层。这里的 C ++ 源代码:

void isometric::brush_circle(int x0,int y0,int z0,int r)
    {
    r--; if (r<0) return;
    int tp=16;  // filling tile
    int x,y,rx,ry,rxx,ryy,rr=(r+1)*(r+1)-(r>>1);

    if ((z0>=0)&&(z0<gzs))
    for (rx=-r,x=x0+rx,rxx=rx*rx;rx<=r;rx++,x++,rxx=rx*rx)
     for (ry=-r,y=y0+ry,ryy=ry*ry;ry<=r;ry++,y++,ryy=ry*ry)
      if (rxx+ryy<rr)
       if ((x>=0)&&(x<gxs)&&(y>=0)&&(y<gys))
        map[z0][y][x]=tp;

    _redraw=true;
    }

它使用圆盘/圆等式:

(x-x0)^2+(y-y0)^2<=r^2

使用一些整数舍入调整以获得更好的效果。该代码基于我的这个等距引擎:

应用边缘平滑后,结果如下:

smooth

如果要实现半单元格半径分辨率,您可以获得更多选项,例如:

  1. 使用浮动或定点算术
  2. 使用diameter作为调用操作数而不是radius 所以你只需相应地更新等式(避免舍入)
  3. 我选择#2 ,所以请使用:

    (x-x0)^2+(y-y0)^2<=(d^2)/4
    

    我得到的最接近的是(d=2的特殊情况):

    void isometric::brush_circle(int x0,int y0,int z0,int d)
        {
        if ((z0<0)||(z0>=gzs)) return;
        int tp=16;  // filling tile
        int x,y,rx,ry,rxx,ryy,r=(d>>1)+1,rr=((d*d)-(d>>1))>>2;
        if (d==2)
            {
            x=x0; y=y0; if ((x>=0)&&(x<gxs)&&(y>=0)&&(y<gys)) map[z0][y][x]=tp;
            x++;        if ((x>=0)&&(x<gxs)&&(y>=0)&&(y<gys)) map[z0][y][x]=tp;
            y++;        if ((x>=0)&&(x<gxs)&&(y>=0)&&(y<gys)) map[z0][y][x]=tp;
            x--;        if ((x>=0)&&(x<gxs)&&(y>=0)&&(y<gys)) map[z0][y][x]=tp;
            }
        else
         for (rx=-r,x=x0+rx,rxx=rx*rx;rx<=r;rx++,x++,rxx=rx*rx)
          for (ry=-r,y=y0+ry,ryy=ry*ry;ry<=r;ry++,y++,ryy=ry*ry)
           if (rxx+ryy<=rr)
            if ((x>=0)&&(x<gxs)&&(y>=0)&&(y<gys))
             map[z0][y][x]=tp;
        _redraw=true;
        }
    

    raw smooth

    看起来它需要添加至少一个特殊情况,或者稍微调整rr常数。

    [编辑1]午餐后再教一些......

    从整数的角度来看,更好的方程是:

    4*( (x-x0)^2 + (y-y0)^2 ) <= (d^2)
    

    final

    void isometric::brush_circle(int x0,int y0,int z0,int d)
        {
        if ((z0<0)||(z0>=gzs)) return;
        int tp=16;  // filling tile
        int x,y,rx,ry,rxx,ryy,r=(d>>1)+1,dd=(d*d)+d;
        if (d==2)
            {
            x=x0; y=y0; if ((x>=0)&&(x<gxs)&&(y>=0)&&(y<gys)) map[z0][y][x]=tp;
            x++;        if ((x>=0)&&(x<gxs)&&(y>=0)&&(y<gys)) map[z0][y][x]=tp;
            y++;        if ((x>=0)&&(x<gxs)&&(y>=0)&&(y<gys)) map[z0][y][x]=tp;
            x--;        if ((x>=0)&&(x<gxs)&&(y>=0)&&(y<gys)) map[z0][y][x]=tp;
            }
        else
         for (rx=-r,x=x0+rx,rxx=rx*rx;rx<=r;rx++,x++,rxx=rx*rx)
          for (ry=-r,y=y0+ry,ryy=ry*ry;ry<=r;ry++,y++,ryy=ry*ry)
           if ((rxx+ryy)<<2<dd)
            if ((x>=0)&&(x<gxs)&&(y>=0)&&(y<gys))
             map[z0][y][x]=tp;
        _redraw=true;
        }