繁体   English   中英

如何更快地使屏幕无效?

[英]How to invalidate screen faster?

在我目前的项目(生命游戏)中,我需要重绘屏幕,因为大约有200个物体在移动。 我可以想到两种方法,但没有任何线索会更快:

我可以:
1)为整个屏幕调用Invalidate(),并在Paint处理程序中有以下内容:

void Paint(object sender, PaintEventArgs e)
{
   foreach(Cell c in ListOfCells)
          {
             e.DrawImage(c,c.x,c.y);
          }
}

2)或者我可以使每个单元格的屏幕的每个部分无效:

public void MyInvalidate()
{
  foreach(Cell c in ListOfCells)
              {
                 Invalidate(c.X,c.Y,c.Width,c.Height);
              }


}

并拥有与上面相同的处理程序

现在,第一条规则始终是“不要过早优化”。 您需要确保需要优化清洁代码。

现在,在生命游戏中,你最初看的是一个非常空的屏幕。 然而,随着比赛的进行,越来越多的细胞将被填满,最终将成为整个棋盘。 现在,GOL规则规定大多数这些细胞将从一个周期变为另一个周期。

您还需要通过“使区域无效”来理解它的含义。 在Windows中,无效区域“加起来”以形成“更新区域”,以便WM_PAINT消息可以告诉程序要绘制屏幕的哪个部分。 在Paint事件处理程序中,使用RectVisible来确定是否要刷新单元格。

换句话说,做方法1的“成本”(假设板尺寸为n):

(n x n) x (redraw cell + update cell on screen)

请注意,我假设您在绘制单元格之前记得要清除屏幕,否则在上一个循环中过去“活着”的单元格将保留在屏幕上。 因此,这假设您要在整个屏幕上绘制活动单元格或空白单元格。

做方法2的“成本”:

(v) x (redraw cell + update cell on screen) + (n x n) x (RectVisible call)

其中v =改变的细胞数(见下面的警告)。

因此,方法1比方法2更快,如果:

(n x n) x redraw < v x redraw + (n x n) x RectVisible
n2 x (redraw - RectVisible) < v x redraw
v > ((redraw - RectVisible) / redraw) x n2
v > (1 - RectVisible/redraw) x n2

换句话说,改变的单元的数量必须大于1减去(RectVisible cost / redraw cost)的比率。 现在,与在屏幕上绘制位图相比, RectVisible通常非常快,特别是如果您的单元格具有高分辨率。 因此,Rectvisible / redraw通常是一个非常小的数字,只有当有> 99%的电路板同时改变时,方法1才比方法2更快,这是不太可能的。

换句话说,您会发现方法2通常会产生更高的性能,因为如果要在剪切区域之外(即不在更新区域内)绘制图像, DrawImage通常会跳过整个操作。

CAVEAT - 您的代码,因为它不起作用

但是,方法2中的代码将不起作用。 你必须记住在最后一个循环中“清空”曾经有“活”细胞的“死”细胞。 换句话说,您使“已更改”的单元格无效,而不仅仅是那些“活着”的单元格。 细胞是“活着”多个循环, 不需要无效。 因此, MyInvalidate方法中的逻辑存在缺陷。

如果您坚持使用与第一个相同的Paint事件处理程序,第二个代码将没有任何好处,因为基本上您将多次重绘所有单元格(因为对于每个单元格,您将重绘所有其他单元格细胞也是如此)。 要解决此问题,您可以检查e.ClipRectangle ,并仅重绘该矩形内的单元格。

但是,如果您屏幕上唯一的东西是单元格(因此您没有大量其他显示元素,例如UI控件),那么第一种方法是您将获得的最佳方法(即只是无效( )整个屏幕)。 仅当您使大量未更改的屏幕区域无效时,才会出现性能损失。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM