0

正如您可能从下面的代码中看出的那样,我对 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)));
        }
    }
4

1 回答 1

0

以防万一有人遇到类似的性能问题,我将全面回答这个问题,感谢下面评论中的人向我指出了一些事情。

导致问题的行很可能很明显:

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

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

所以我只是在第一次加载瓦片集时将所有瓦片缓存到一个数组中,如下所示:

    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 自己完成。

于 2013-02-27T10:05:48.707 回答