在iso网格上用于平铺地图画笔的算法比Midpoint Circle更好

Xarbrough

我正在从事这个iso网格游戏(更精确的是:等轴测投影,在典型的菱形布局中索引),并且想要像在任何图像编辑软件中一样,实现圆形画笔以在地图上绘制瓷砖。从中点圆算法开始,但立即注意到,结果看起来不像我想要的1到7之间的小画笔大小。

在此处输入图片说明

我宁愿有这样的事情:

在此处输入图片说明

忽略第一个圆圈没有被填充,那当然很容易。是否有合适的算法在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;
}
光谱

您未指定等轴测网格的布局。我假设使用菱形,因为在此实施起来更容易。但是,在整数算法中,实际上很难实现半径的半像元分辨率。对于完整的细胞分辨率半径圆盘填充,请使用for带有内圆测试的简单2个嵌套s。结果看起来像这样:

生的

只需忽略我的等距编辑器的树和图块列表覆盖图。这是为此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

进行一些整数舍入调整,以获得更好的外观。该代码基于我的这个等距引擎:

在应用边缘平滑之后,结果是这样的:

光滑的

如果要实现半像元半径分辨率,则可以使用更多选项,例如:

  1. 使用浮点或定点算法
  2. 使用diameter和调用操作数,而不是radius那么您只需更新相应公式(凑整回避)

我去#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;
    }

生的 光滑的

看起来它需要添加至少一个特殊情况,或者需要对rr常量进行更多调整

[Edit1]午餐后,还教了更多...

从整数的角度来看,更好的等式是:

4*( (x-x0)^2 + (y-y0)^2 ) <= (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,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;
    }

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章