如何使用XNA创建类似Paint的应用程序?

Bug*_*boy 3 mouse xna paint line draw

这里介绍使用XNA以编程方式绘制线条的问题.但是,我希望允许用户在画布上绘图,就像使用绘图应用程序(如MS Paint)一样.

这当然要求鼠标指针位置中的每个x和/或y坐标改变,以导致在画布上以蜡笔颜色实时绘制线的另一"点".

在鼠标移动事件中,为了逐点绘制线,XNA API考虑因素发挥了什么作用?当然,从字面上看,我并不是这样画线,而是一系列"点".每个"点"可以并且可能应该大于单个像素.想想用毡尖笔画画.

Luc*_*ius 7

您提供的文章提出了一种使用基元绘制线条的方法; 换句话说,矢量图形.像Paint这样的应用程序主要是基于像素的(即使像Photoshop这样的更高级的软件具有矢量和光栅化功能).

位图编辑器

既然你希望它是"类似绘画",我肯定会采用基于像素的方法:

  1. 创建颜色值网格.(扩展System.Drawing.Bitmap类或实现自己的类.)
  2. 启动(游戏)循环:
    • 处理输入并相应地更新网格中的颜色值.
    • 将位图转换为Texture2D.
    • 使用精灵批处理或自定义渲染器将纹理绘制到屏幕上.
  3. 如果需要,保存位图.

在位图上绘图

我在答案的底部添加了我正在使用的图像类的粗略草稿.但无论如何,代码应该是不言自明的.

如前所述,您还需要实现一种将图像转换为Texture2D并将其绘制到屏幕的方法.


首先,我们创建一个新的10x10图像并将所有像素设置为白色.

var image = new Grid<Color>(10, 10);
image.Initilaize(() => Color.White);
Run Code Online (Sandbox Code Playgroud)

白色10*10像素网格

接下来我们设置一个画笔.画笔本质上只是一个应用于整个图像的功能.在这种情况下,该函数应将指定圆内的所有像素设置为深红色.

// Create a circular brush
float brushRadius = 2.5f;
int brushX = 4;
int brushY = 4;
Color brushColor = new Color(0.5f, 0, 0, 1); // dark red
Run Code Online (Sandbox Code Playgroud)

白色10*10颜色网格,圆形和十字形,定义画笔区域和中心

现在我们应用画笔.请参阅我的回答,了解如何识别圆圈内的像素.您可以使用鼠标输入作为画笔偏移,并使用户能够实际绘制位图.

double radiusSquared = brushRadius * brushRadius;

image.Modify((x, y, oldColor) =>
{
    // Use the circle equation
    int deltaX = x - brushX;
    int deltaY = y - brushY;
    double distanceSquared = Math.Pow(deltaX, 2) + Math.Pow(deltaY, 2); 

    // Current pixel lies inside the circle
    if (distanceSquared <= radiusSquared)
    {
        return brushColor;
    }

    return oldColor;
});
Run Code Online (Sandbox Code Playgroud)

白色10*10颜色网格,圆圈内的所有像素都设置为深红色

您还可以在画笔颜色和旧像素之间进行插值.例如,您可以通过让混合量取决于画笔中心与当前像素之间的距离来实现"柔和"画笔.

白色10*10颜色网格,带有柔和的深红色圆点

画一条线

为了绘制手绘线,只需重复应用刷子,每次使用不同的偏移量(取决于鼠标移动):

通过重复应用圆形画笔绘制线条


自定义图像类

我显然跳过了一些必要的属性,方法和数据验证,但你明白了:

public class Image
{
    public Color[,] Pixels { get; private set; }

    public Image(int width, int height)
    {
        Pixels= new Color[width, height];
    }

    public void Initialize(Func<Color> createColor)
    {
         for (int x = 0; x < Width; x++)
         {
             for (int y = 0; y < Height; y++)
             {
                  Pixels[x, y] = createColor();
             }
         }
    }

    public void Modify(Func<int, int, Color, Color> modifyColor)
    {
         for (int x = 0; x < Width; x++)
         {
             for (int y = 0; y < Height; y++)
             {
                  Color current = Pixels[x, y];
                  Pixels[x, y] = modifyColor(x, y, current);
             }
         }
    }
}
Run Code Online (Sandbox Code Playgroud)