2015-12-14 21 views
6

申し訳ありませんが、私はこのトピックについていくつかの調査を行いましたが、私が見つけた解決策のほとんどは問題を解決すると主張しましたが、私はちょうど単純な小さなパーティクルエンジンを実装する初期段階にあります。何も狂っていません。私は退屈からやっています。これまでWinFormsでこのようなことはしていませんでしたが、確かにC/C++を使っていますが、これは新しいものです。以下は私がスクリーンにパーティクルを描くために使用しているコードですが、パーティクルのボイラープレートコードは問題なく動作しますので、実際のゲームのループについてもっと興味があります。ここで画面上のC#WinFormsプログラムのちらつき

私はに実行している問題は、それが時にはそれいつでも画面がクリアされ、更新取得され、それはこのひどいちらつきを取得しており、それだけではなくなく、更新のためのメインコードであると

public MainWindow() 
    { 
     this.DoubleBuffered = true; 
     InitializeComponent(); 
     Application.Idle += HandleApplicationIdle; 
    } 

    void HandleApplicationIdle(object sender, EventArgs e) 
    { 
     Graphics g = CreateGraphics(); 

     while (IsApplicationIdle()) 
     { 
      UpdateParticles(); 
      RenderParticles(g); 
      g.Dispose(); 
     } 
    } 

    //Variables for drawing the particle 
    Pen pen = new Pen(Color.Black, 5); 
    Brush brush = new SolidBrush(Color.Blue); 
    public bool emmiter = false; 

    private void EmitterBtn_Click(object sender, EventArgs e) 
    { 
     //Determine which emitter to use 
     if (emmiter == true) 
     { 
      //Creates a new particle 
      Particle particle = new Particle(EmitterOne.Left, EmitterOne.Top, .5f, .5f, 20, 20); 
      emmiter = false; 
     } 
     else if(emmiter == false) 
     { 
      Particle particle = new Particle(EmitterTwo.Left, EmitterTwo.Top, -.5f, .5f, 20, 20); 
      emmiter = true; 
     } 
    } 

    public void RenderParticles(Graphics renderer) 
    { 


     Invalidate(); 
     Thread.Sleep(0); 

     //Iterate though the static list of particles 
     for (int i = 0; i < Particle.activeParticles.Count; i++) 
     { 


      //Draw Particles 
      renderer.DrawRectangle(pen, Particle.activeParticles[i].x, 
           Particle.activeParticles[i].y, 
           Particle.activeParticles[i].w, 
           Particle.activeParticles[i].h); 
     } 
    } 

    public void UpdateParticles() 
    { 
     for (int i = 0; i < Particle.activeParticles.Count; i++) 
     { 
      //Move particles 
      Particle.activeParticles[i].MoveParticle(); 
     } 
    } 

を再描画パーティクルを放出するたびに私はしません。

フォームは、基本的に画面上の目に見えない場所としてラベルを使用して、各パーティクルをどこにレンダリングするかを指定します。

とにかく、私はこのトピックを見てきましたが、何も修正されていないものは、現在の実装は最もちらつき/遅いですが、問題を解決していません。

ご協力いただきありがとうございます。

EDIT *エフェクトボタンをクリックするたびにグラフィックスオブジェクトの割り当てを解除していないことを認識しましたが、ちらつきがまだ残っています。

+0

'無効化();'全体の制御領域をきれいに拭いさせるであろう、したがってフリッカ。通常はオフスクリーンのバッファーに描画しますが、単に点を描画するだけなので、新しいドットを描画する前に古いドットの位置を覚えて消去することができます。それはある点まで働く。私が言ったように、オフスクリーンのバッファが好まれます。あなたのアニメーションのスピードは、 'Application.Idle'に基づいてひどく変動します。タイマーの使用を検討することをお勧めします。 – MickyD

+0

興味深いことに、私が読んだ他のものは、同じことを考えていたにもかかわらずタイマーが信頼できるものではないと言います。私はそれを試してみなければならないかもしれません。 –

+0

'System.Windows.Forms.Timer'は、特に30 FPSというターゲットを設定したい場合にこのようなことができます。'Timer'はそれを処理するのに十分なコースです(私たちは超精密タイマーの後ではありません)。タイマーの代わりにアプリケーションをアイドル状態にする問題は、マウスを動かすと、Windowsは実際にあなたと私のC++ MFCの日に見たアプリアイドルメッセージの量を減らし、C# :) – MickyD

答えて

5

表示されているペイントアーティファクトを取り除くには、ダブルバッファリングが必要です。言い換えれば、シーンをバックバッファにレンダリングします。バックバッファは、準備が整い次第、スクリーン面に素早くブリッジされます。これはWinformsのビルトイン機能です。フォームコンストラクタでDoubleBufferedプロパティをtrueに設定するだけです。は、がペイントイベントを使用してそれを利用する必要があります。 OnPaint()をオーバーライドし、RenderParticles(e.Graphics)を呼び出します。

タイミングを気にする必要があります。現在、UIスレッドは100%コアとアニメーションの速度を完全に燃やしています。パーティクルの数とマシンのスピードによって異なります。 Application.Idleの代わりに、ツールボックスからTimerをフォームにドロップします。 Tickイベントハンドラで、UpdateParticles()およびthis.Invalidate()を呼び出して、Paintイベントを再度発生させます。タイマーのIntervalプロパティ値が重要な場合は、15または31 msec(64または32 FPS)を選択して再現性の高い更新レートを取得します。

マシンがビジーであるか、遅すぎるか、またはUIスレッド上の他のコードを実行する必要がある場合、タイマはTickイベントを遅延またはスキップするだけです。アニメーションに影響しないことを確認するには、固定量で粒子を移動するのではなく、実際の経過時間を測定する必要があります。 Environment.TickCount、DateTime.UtcNowまたはStopwatchは、真の経過時間を測定するのに適した方法です。

関連する問題