在绘制事件运行缓慢时将波浪形图绘制到屏幕上

本文关键字:绘制 波浪形 屏幕 事件 运行 缓慢 | 更新日期: 2023-09-27 18:00:47

从下面的代码中可以看出,我对C#很陌生。对于我的第一个项目(作为一种测试),我制作了一个2D级别的编辑器,它有5层。在下面的代码中,我要学习一个短名单字典,它是每次地图更改时生成的,只包含填充的瓦片,而不是使用for(x for(y for z(draw graphics)),它必须检查网格的每个部分是否有任何东西。

它运行得很好,直到我在屏幕上有大约30个磁贴,然后它开始运行得很慢,就像真的很颠簸。此绘制事件仅在需要时调用,不在计时器上运行,仅在铺设新瓷砖或鼠标光标悬停在新块上时运行。所以我猜问题出在图像被实际绘制到屏幕上的部分,就像有东西在堆积一样。

DrawImage()函数下面注释的行是为了测试只绘制矩形而不是波浪集的一部分是否更快。确实如此!!我很抱歉我听起来很傻,但请记住,这是我的第一个项目,不知道在哪里可以找到关于这个特定主题的答案。

谢谢!,下面是我的绘画代码

public void editor_Paint(object sender, PaintEventArgs e)
    {
        Graphics g = e.Graphics;
        string[] keys;
        string[] values;
        foreach(KeyValuePair<string, string> dict in map.shortlist){
            keys = dict.Key.Split('|');
            values = dict.Value.Split('|');
            int xpos = Convert.ToInt16(keys[0]);
            int ypos = Convert.ToInt16(keys[1]);
            int zpos = Convert.ToInt16(keys[2]);
            Tile tile = map.data[xpos, ypos, zpos];
            if (tile.type == "tile")
            {
                Bitmap img = tileset.bitmap.Clone(new Rectangle(tile.x * 16, tile.y * 16, 16, 16), tileset.bitmap.PixelFormat);
                g.DrawImage(img, new Point(xpos * 16, ypos * 16));                                       
                //g.DrawRectangle(Pens.Blue, new Rectangle(new Point(xpos * 16, ypos * 16), new Size(16,16)));                                       
            }
        }
        if (selector.MouseOver == true)
        {
            int tileSize = Preferences.blockSize;                
            Pen pen = new Pen(Color.Red, 1);                
            g.DrawRectangle(pen, new Rectangle(new Point((MouseX / tileSize) * tileSize, (MouseY / tileSize) * tileSize), new Size(tileSize, tileSize)));
        }
    }

在绘制事件运行缓慢时将波浪形图绘制到屏幕上

如果有人遇到类似的性能问题,我会全面回答这个问题,感谢下面评论中的人向我指出了一些问题。

造成问题的原因很可能是显而易见的:

Bitmap img = tileset.bitmap.Clone(new Rectangle(tile.x * 16, tile.y * 16, 16, 16), tileset.bitmap.PixelFormat);

当它遇到瓷砖时,必须在每个foreach上创建一个新的位图,并从原始瓷砖集位图中选择一个正方形。这样做30-40次是相当劳动密集的。

因此,当tileset第一次加载时,我只是将所有tiles缓存到一个数组中,如下所示:

    private void GenerateBitmapTiles() {
        Bitmap bitmap = new Bitmap(TilesetImageFile);
        bitmaps = new Bitmap[image.Width / 16, image.Height / 16];
        for (int x = 0; x < image.Width / 16; x++)
        {
            for (int y = 0; y < image.Height / 16; y++)
            {
                bitmaps[x, y] = bitmap.Clone(new Rectangle(x * 16, y * 16, 16, 16), bitmap.PixelFormat);
            }
        }
        bitmap.Dispose();
    }

然后我可以通过做以下操作来拉瓷砖:

g.DrawImage(bitmap[x, y], new Point(xpos * 16, ypos * 16));

但是!看完下面的评论后,我意识到winforms是一种更古老的技术。。Winforms并没有过时,但WPF是最新的技术,在压力下可以表现得更好,加上硬件加速。

我已经开始在WPF中重建项目,绘画不是问题。与其说:这是我的数据,现在每次屏幕绘制时,我都想在这里和这里绘制这个对象,在WPF中,你只需要说,我想在这里,这里和这里画我的对象。其余部分由WPF自己完成。