65.9K
CodeProject 正在变化。 阅读更多。
Home

行进的蚂蚁

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.93/5 (18投票s)

2008年7月14日

CPOL

3分钟阅读

viewsIcon

68814

downloadIcon

935

学习如何轻松高效地创建行进的蚂蚁。

引言

行进蚁群是在图形程序中常见的现象,它们用于显示用户选择的区域。通常,这个区域可以是各种形状的组合,甚至可以是用户选择的区域。本文将尝试向您展示如何创建您自己的行进蚁群程序。

背景

最好您了解 GDI+ 的基础知识。我将尝试展示您创建工作程序所需的一切。

设置选定区域

该技术最重要的部分是一对对象:一个 GraphicsPath 对象和一个 Region 对象。 Region 位于 System.Drawing 中,GraphicsPath 位于 System.Drawing.Drawing2D 中。虽然不是必须的,但我创建了一个单独的类来存储我的 GraphicsPathRegion

代码的核心就在这里

public void AddRectangle(Rectangle rectangle)
{
    _gp.AddRectangle(rectangle);
    _region.Union(_gp);
}

public void AddCircle(Rectangle rectangle)
{
    _gp.AddEllipse(rectangle);
    _region.Union(_gp);
}

public void AddFreeform(Point[] points)
{
    _gp.AddPolygon(points);
    _region.Union(_gp);
}

在初始化我的 GraphicsPath (_gp) 和 Region (_region) 之后,我有一些方法可以向它们添加新的形状。Region 是必要的,因为它是唯一可以组合这些各种形状的类。

创建蚂蚁

我的代码的另一部分是渲染代码。为了创建行进蚁群的效果,我使用了一个狡猾的小技巧。通常,GraphicsPath 无法进行组合,因此您会得到来自多个不同矩形的线条(而不仅仅是外轮廓线)。我创建一个 Bitmap,然后用 Region 填充线条的中心,这消除了所有不必要的线条。然后,我将刚刚填充的颜色设置为 Bitmap 的透明颜色,并将其绘制在我的表面上。

private void Canvas_Paint(object sender, PaintEventArgs e)
{
    e.Graphics.DrawImage(_image, new Rectangle(0, 0, 
                         _image.Width, _image.Height));
    //draws your image

    e.Graphics.FillRegion(new SolidBrush(Color.FromArgb(128, 0, 0, 255)), 
                          _region);
    //fills the selected region with 
    //a semi-transparent blue for a nice effect

    Pen pen = new Pen(Color.White, 1);
    pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
    pen.DashPattern = new float[2] { 3, 3 };
    //these lines set up a pen that will draw dashed white lines

    Bitmap ant = new Bitmap(CanvasPanel.Width, CanvasPanel.Height);
    Graphics g = Graphics.FromImage(ant);
    //creates a Graphics object from the Bitmap we will draw the ants on

    g.Clear(Color.Magenta);
    //makes the Bitmap Magenta so that the outsides will be transparent

    g.DrawPath(new Pen(Color.Black), _graphicsPath);
    g.DrawPath(pen, _graphicsPath);
    //draws a black outline (for underneath) 
    //and the dashed white line on top

    g.FillRegion(new SolidBrush(Color.Magenta), _region);
    //fills in the middle so the extra lines don't show

    ant.MakeTransparent(Color.Magenta);
    //makes the areas not covered by the marching ants transparent

    e.Graphics.DrawImageUnscaled(ant, 0, 0);
    //draw the ants on to the image
}

修复中心

因为 GraphicsPathRegion 的大小相同,所以在 GraphicsPath 内部绘制 Region 实际上会模糊一些蚂蚁。为了解决这个问题,我们可以使用 GraphicsPath 类的一个便捷函数 - Widen。我发现扩大 1 或 2 个像素效果最好。这是我用来修复此问题的函数

public GraphicsPath Line()
{
    GraphicsPath gp = new GraphicsPath();
    if (_gp.PointCount > 0)                
    {        
        //I had to add this if statement so the program 
        //wouldn't crash if my GraphicsPath was still empty
        gp.AddPath(_graphicsPath, false);
        gp.Widen(new Pen(Color.White, 2));
    }
    return gp;
}

我使用此函数是为了避免在每一帧或每次添加新形状时都扩大我的原始 GraphicsPath 对象(这是一个容易犯的错误,可能很快导致您的程序崩溃)。

动画化蚂蚁

为了动画化蚂蚁,我仅仅创建了一个 Timer 并在每个 tickCount 重绘图像。我确信有更有效的方法来做到这一点(例如使正确的区域失效),但目前这更简单。

private void AntTimer_Tick(object sender, EventArgs e)
{
    _antOffset++;
    if (_antOffset > 50) _antOffset = 0;
    Canvas.Refresh();
}

然后,在代码的 OnPaint 部分,您需要添加一行代码来考虑此偏移量

pen.DashOffset = _antOffset;

将此代码与设置画笔属性的其他代码放在一起,应该会为您提供一个功能齐全的行进蚁群程序。

关注点

非常感谢 The Secret of Marching AntsMarching Ants Revisited 的作者。他们的程序给了我一些很棒的想法,尽管我认为我的程序更高效,并且允许更复杂的路径。

其他

这是我的第一篇文章,请给我反馈。 :-)

历史

  • 2008/7/14 - 原始上传
  • 2008/7/23 - 源代码已更新
© . All rights reserved.