2009-07-21 3 views
3

アニメーションのCanvasに多くのピクセルを描画するこのアルゴリズムがあります。しかし、私はアニメーションの速度を制御することはできませんし、非常に高速描画しているので、私はThread.Sleep(1)を追加しましたが、 私はストーリーボードのアプローチを試みましたが、それは非常に遅くなってしまいました。Thread.Sleep(1); Silverlightアニメーションでは遅すぎるのですが、代替方法はありますか?

ループの速度を落とすためのThread.sleepの代替手段がありますか?

void DrawGasket(object sender, DoWorkEventArgs e) 
    { 
     Random rnd = new Random(); 
     Color color = Colors.White; 
     while (Counter <= noOfPx) 
     { 
      switch (rnd.Next(3)) 
      { 
       case 0: 
        m_lastPoint.X = (m_top.X + m_lastPoint.X)/2; 
        m_lastPoint.Y = (m_top.Y + m_lastPoint.Y)/2; 
        color = Colors.White; 
        break; 
       case 1: 
        m_lastPoint.X = (m_left.X + m_lastPoint.X)/2; 
        m_lastPoint.Y = (m_left.Y + m_lastPoint.Y)/2; 
        color = Colors.Orange; 
        break; 
       case 2: 
        m_lastPoint.X = (m_right.X + m_lastPoint.X)/2; 
        m_lastPoint.Y = (m_right.Y + m_lastPoint.Y)/2; 
        color = Colors.Purple; 
        break; 
      } 
      Dispatcher.BeginInvoke(() => 
      { 
       var px = new Rectangle { 
             Height = m_pxSize, 
             Width = m_pxSize, 
             Fill = new SolidColorBrush(color) 
             }; 
       Canvas.SetTop(px, m_lastPoint.Y); 
       Canvas.SetLeft(px, m_lastPoint.X); 
       can.Children.Add(px); 
       lblCounter.Text = Counter.ToString(); 
      }); 
      Counter++; 
      Thread.Sleep(1); 
     } 
    } 

答えて

13

すべての反復ではなく、ループを通じてN回の反復をスリープ状態にすることはできませんか?

+0

Doh ...シンプルな方が優れていました。 – Qwark

4

簡単な方法は次のとおりです。特定の時刻に描画する...各ループ中に何時に表示されるかを確認します。それが "時間"(どんなことであれ)であれば、それを決定し、次に描画/更新します。それ以外の場合は、ループします。 (たとえば、毎秒10回の更新を行い、更新したばかりの場合は、現在の時刻を変数に格納してからその変数と比較します。10分の1秒後までは、

このループ内で実行する必要がある限り、これは悪くありません。しかし、このループが完了する必要がある場合は、何かが起きる前に待っているだけで多くのCPUサイクルを焼くでしょう。

あなたが好奇心を得て、このようにしたい場合は、どれだけの時間が経過したかを見てから、正しい量だけビジュアルを更新することができます。たとえば、オブジェクトを1秒間に30ピクセル動かしたい場合は、正確にどこで更新すればよいのですか(たとえば.0047秒が経過した場合は、0.141ピクセル移動する必要があります)。その値を保存します。もちろん、視覚的には、ループのもう1つのラウンドまでは全く移動しませんが、移動するときの正確さと、コンピュータの速度ではなく、の時間であるで決定されます。この方法では、マシンの速度に関係なく、毎秒30ピクセル移動します。遅いマシンでは急激に変化します。

+0

ちょっと複雑かもしれませんが、時間アイデアのようなものですが、別のコンピュータでほぼ同じ速度でループを実行できます。それは遅い速度よりも速い速度のコンピュータでより頻繁に寝るでしょう。 –

+0

+1は(本質的に)タイミングループであることを示唆する。他にもオプションがあります(たとえば、メモリにペイントし、新しいイメージを表示するときにのみイメージを反転するなど)が、この問題に直接対処します。 –

+0

これは後で実装しようとします。これは、アニメーションを行うためのより良い方法だからです。しかし今のところ私はmattnewportのソリューションを使っています。 – Qwark

3

1つのオプションは、それぞれの時間を寝ないように、次のようになります(またはのThread.sleepなし

if(Counter % 2 == 0) Thread.Sleep(1);

3

)、レンダリング速度は、お使いのシステムがどのように速くすることにより、またはどのくらいの時間、あなたによって決定されますプロセスが得られる。 - >悪い!

現在、ビデオゲームが書かれているアプローチを使用する必要があります。現在の時刻を追跡し、BeginInvoke()を1秒間にx回だけ呼び出します(xは1秒あたりのフレーム数です)。

BeginInvoked関数では、どれだけ描画され、描画する必要があるかをチェックします。特に、すべての単一のRectangleに対してBeginInvokeを使用しないでください。 Thread.Sleep()がなくても、常にコンテキストスイッチです。

4

Silverlightがフレームを描画するたびにCompositionTarget.Renderingイベントが発生します。カスタム描画コードを書き込むのに適しています。タイマーのような他のメカニズムを使用して、 "ゲーム時間"を追跡し、描画コードとは別のスレッド(または少なくとも別々の実行パス)でモデルを適切に調整することができます。そのようにしてUIを描画するときには、実行する計算がなく、モデルの現在の状態をペイントするだけです。基本的には、Dispatcher.BeginInvokeのコードをCompositionTarget.Renderingのイベントハンドラに移動するだけでよいでしょう。

関連する問題