我第一次在这里问一个问题,如果我做错了,请纠正我。
我国际象棋的图片: http://img842.imageshack.us/img842/2695/65744343.png
每次移动一块它都会滞后约1秒钟。每件和瓷砖都有一个图像,正好有96个图像。每当我移动一块时,它都会用黑色清除所有内容,然后更新图形。
在国际象棋的早期阶段,我没有任何图像,而是使用了不同的颜色,只有几件没有明显的滞后,这件作品瞬间移动。
public void updateGraphics(PaintEventArgs e, Graphics g, Bitmap frame)
{
g = Graphics.FromImage(frame);
g.Clear(Color.Black);
colorMap(g);
g.Dispose();
e.Graphics.DrawImageUnscaled(frame, 0, 0);
}
函数colorMap(g)如下所示:
private void colorMap(Graphics g)
{
for (int y = 0; y < SomeInts.amount; y++)
{
for (int x = 0; x < SomeInts.amount; x++)
{
//Tiles
Bundle.tile[x, y].colorBody(g, x, y);
//Pieces
player1.colorAll(g);
player2.colorAll(g);
}
}
}
colorAll函数执行每个colorBody(g)函数,如下所示:
public void colorBody(Graphics g)
{
//base.colorBody() does the following: body = new Rectangle(x * SomeInts.size + SomeInts.size / 4, y * SomeInts.size + SomeInts.size / 4, size, size);
base.colorBody();
if (team == 1)
{
//If its a white queen
image = Image.FromFile("textures/piece/white/queen.png");
}
if (team == 2)
{
//If its a black queen
image = Image.FromFile("textures/piece/black/queen.png");
}
g.DrawImage(image, body);
}
最终移动片段的功能:
public void movePiece(MouseEventArgs e)
{
for (int y = 0; y < SomeInts.amount; y++)
{
for (int x = 0; x < SomeInts.amount; x++)
{
if (Bundle.tile[x, y].body.Contains(e.Location))
{
//Ignore this
for (int i = 0; i < queens.Count; i++)
{
Queen temp = queens.ElementAt<Queen>(i);
temp.move(x, y);
}
//Relevant
player1.move(x, y);
player2.move(x, y);
}
}
}
}
感谢您阅读所有这些!如果我的编码示例不够,我可以建立整个程序的链接。
答案 0 :(得分:7)
您在每次刷新时都会为每个图像调用Image.FromFile
- 每次从磁盘上有效地重新加载每个图像文件。
您是否考虑过加载一次的图片,并将生成的Image
存储在有用的地方? (比方说,一个数组,Image[2,6]
就足够了)
答案 1 :(得分:3)
为什么每次都重新绘制电路板?你不能把电路板留在原处,并在上面显示透明背景的图像吗?这样你就可以将一个图像作为背景(板),再加上64个较小的图像放在网格板上,只需更改每次移动时显示的图像。
这样,你可以让窗户处理绘图...
此外,在应用程序开始时加载碎片的图像。
答案 2 :(得分:1)
除了不在Image.FromFile()
内调用updateGraphics()
(这绝对是您最大的问题)之外,您不应该在每次通话时都尝试重新绘制整个电路板到updateGraphics()
- 大部分时间,只有一小部分董事会无效。
PaintEventArgs
包含一个参数ClipRectangle
,它指定了电路板的哪个部分需要重绘。看看你是否无法弄清楚哪些瓷砖与那个矩形相交,只能重绘这些瓷砖:)
提示:编写一个函数Point ScreenToTileCoords(Point)
,它取一个屏幕坐标并返回哪个电路板块位于该坐标。然后,您需要重绘的唯一图块是
Point upperLeftTileToBeDrawn = ScreenToTileCoords(e.ClipRectangle.Left, e.ClipRectangle.Top);
Point lowerRightTileToBeDrawn = ScreenToTileCoords(e.ClipRectangle.Right - 1, e.ClipRectangle.Bottom- 1);
另外,请确保您的控件是双缓冲的,以避免撕裂。这比上述评论中的@Steve B链接要简单得多;假设这是UserControl
,只需设置
this.DoubleBuffered = true;
答案 3 :(得分:0)
那么,这个:
不要清除整个电路板,只清除需要清除的部分。
替代:
更新到WPF - 它将绘图移动到图形卡 - 只需以智能方式移动棋子(即每个棋子都有一个控件/对象)。