2016-11-28 16 views
0

私は現在、C#、GDIを使用して2Dゲームエンジンを作り、簡単なフレームキャップをセットアップしています。ゲームは60fpsしかレンダリングできません。C#GDI Game Loop(FPS Counter)

私が知っている限り、コードに問題はありませんが、私は60fps以上のレンダリングをよりクリーンな方法で行いたいと思います。ここで

は、任意の助けがあなたのシナリオでは

 public void Run() 
    { 
     window.Show(); 
     window.Focus(); 

     Initialize(); 

     isRunning = true; 
     canRender = true; 

     timer = new Stopwatch(); 
     timer.Start(); 

     // the amount of milliseconds needed to pass before rendering next frame 
     double frameCapCounter = 16.666666; 

     while (isRunning) 
     { 
      Application.DoEvents(); 

      if (window.Focused) 
      { 
       if (timer.ElapsedMilliseconds >= frameCapCounter) 
       { 
        canRender = true; 
        frames += 1; // update amount of frames 
        frameCapCounter += 16.666666; // increment counter 
       } 
       else 
       { 
        canRender = false; 
       } 

       // this is used to check if a second has passed, and if so 
       // we set the fps variable to the amount of frames rendered 
       // and reset all variables. 
       if (timer.ElapsedMilliseconds >= 1000) 
       { 
        fps = frames; 
        frames = 0; 
        frameCapCounter = 0; 
        timer.Restart(); 
       } 

       Update(); 
       LateUpdate(); 

       if (canRender) 
        Render(); 
       else 
       { 
        Thread.Sleep(1); 
       } 
      } 
     } 
    } 
+0

SlimDX(https://slimdx.org/docs/html/Managed_Message_Loop.htm)の人たちは、 'Application.DoEvents()'の代わりにこれを使っていました:https://blogs.msdn.microsoft.com/tmiller/ 2005/05/05/my-last-after-render-loops-hopefully / –

答えて

0

、代わりに経過時間を追跡するの、レンダリングされたフレーム、などなど素晴らしいことだ、あなたは、単にキャップにミリ秒数を眠ることができ、私のコードですあなたのFPS、例:

public void Run() 
{ 
    window.Show(); 
    window.Focus(); 

    Initialize(); 

    isRunning = true; 

    while (isRunning) 
    { 
     if (window.Focused) 
     { 
      Update(); 
      LateUpdate(); 
      Render(); 
      Thread.Sleep(16); // hard cap 
     } 
    } 
} 

これに伴う問題は、しかし、睡眠まで、そのコードの残りの部分は16ミリ秒よりも長い時間がかかる可能性があることです。これには、いくつかのパフォーマンス測定を行い、代わりに10msのようなことをすることができます。

もう一つの方法は、アクティブなタイマーを維持することは、次のようになります。

public void Run() 
{ 
    window.Show(); 
    window.Focus(); 

    Initialize(); 

    isRunning = true; 

    long limit = 1000/60; 

    while (isRunning) 
    { 
     if (window.Focused) 
     { 
      timer.Restart(); 
      Update(); 
      LateUpdate(); 
      Render(); 
      while (timer.ElapsedMilliseconds < limit) { 
       Thread.Sleep(0); 
      } 
     } 
    } 
} 

も考慮スリープまでのすべてのコードがより長いを取ることができるという事実を服用しながら、これは「ハード」のキャップを回避します従って、所要時間が経過した場合には「待機」ループに入ることはない。あなたの投稿をコードで考慮することも

、いくつかの注意事項:

まず、あなたは(PictureBoxButtonTextBox、などのような)任意のWindowsフォーム要素を使用していない、代わりに描画されている場合は、すべての要素あなた自身(例えばGraphics.DrawLineのようなものなど)を呼び出す場合は、Application.DoEventsに電話する必要はありません。これにより、呼び出し元のスレッドは他のすべてのWindowsフォームメッセージが処理されるまで待機し、レンダリングループが遅くなります。実際にApplication.DoEventsに電話する必要がある場合は、Render()の後にそれを行う方がよいでしょう。そのために、その関数の呼び出し時間をフレーム制限に含める必要があります。

最後には、非リアルタイムのWindowsシステム上でapproximately 20 millisecondsより少ないもののThread.Sleepを指定するとき、チャンスはSleepが実際に起因するWindowsシステム上のスレッドに専用のタイムスライスに長く眠るということです。したがって、Thread.Sleep(1)は1ミリ秒間スリープします。または 6ミリ秒間スリープする可能性があります。タイムキャップが既に14ミリ秒に設定されている場合は、6ミリ秒のスリープで合計時間が20ミリ秒以上になるため、フレームレートが遅くなります。

0ミリ秒のスリープを指定すると、呼び出しスレッドのタイムスライスの残りの部分を、実行準備ができている同じ優先度の別のスレッドに解放します。他のスレッドが準備できていなければ、呼び出しスレッドは続行します(0-1ミリ秒待機、6秒以上)。 Thread.Yieldも使用できますが、それはカーネルレベルでSleepとは大きく異なる動作をします。

希望に応じることができます。