1

私の現在のプロジェクト(ライフゲーム)では、約200個のオブジェクトが動いているため、画面を再描画する必要があります。私は2つの方法を考えることができますが、より速くなる手がかりはありません。

次のいずれかを実行できます
。1)画面全体に対してInvalidate()を呼び出し、ペイントハンドラーで次のようにします。

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);
              }


}

そして、上記と同じハンドラーを持っています

4

2 に答える 2

4

現在、最初のルールは常に「時期尚早に最適化しない」です。よりクリーンなコードよりもその最適化が必要であることを確認する必要があります。

さて、人生ゲームでは、最初はかなり空の画面を見ています。ただし、ゲームが進むにつれて、ますます多くのセルが埋められ、最終的にはボード全体が埋められます。現在、GOL 規則では、これらのセルのほとんどが 1 つのサイクルから別のサイクルに変化することが規定されています。

また、領域を「無効化」することの意味を理解する必要があります。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 コスト / 再描画コスト) の比率を引いた値より大きくなければなりません。現在、RectVisible特にセルの解像度が高い場合は、ビットマップを画面に描画する場合と比較して、通常は非常に高速です。したがって、Rectvisible/redraw は通常非常に小さい数値であり、方法 1 が方法 2 よりも高速になるのは、たとえばボードの 99% が同時に変更される可能性が低い場合のみです。

言い換えれば、方法 2 は通常DrawImage、クリッピング領域の外側 (つまり、更新領域内ではない) で画像を描画する場合、操作全体をスキップするため、パフォーマンスが向上することがわかります。

警告 - あなたのコードはそのままでは機能しません

ただし、方法 2 のコードは機能しません。最後のサイクルで「生きている」セルを持っていた「死んだ」セルを「空白にする」ことを忘れないでください。つまり、「生きている」セルだけでなく、「変化した」セルを無効にします。複数のサイクルで「生きている」セルを無効にする必要はありません。したがって、MyInvalidateメソッドのロジックには欠陥があります。

于 2011-04-17T08:24:21.570 に答える
0

基本的にすべてのセルを複数回再描画することになるため、最初のコードで使用したのと同じ Paint イベント ハンドラーを使用する場合、2 番目のコードは何の役にも立ちません (セルごとに他のすべてのセルを再描画するため)。セルも同様です)。これを修正するには、e.ClipRectangleをチェックして、その長方形内にあるセルのみを再描画します。

ただし、画面上にセルしかない場合 (つまり、UI コントロールなどの他の表示要素が多数ない場合) は、最初のアプローチが最善の方法です (つまり、単に Invalidate( ) 画面全体)。画面の他の変更されていない領域の多くを無効にしている場合にのみ、パフォーマンスの低下が発生します。

于 2011-04-17T07:44:40.127 に答える