2016-11-28 6 views
0

저는 현재 C#, GDI를 사용하여 2D 게임 엔진을 만들고 간단한 프레임 캡을 설정했습니다. 게임은 60fps 만 렌더링 할 수 있습니다.C# GDI 게임 루프 (FPS 카운터)

코드에 문제가 없다는 것을 알고있는 한, 나는 더 깨끗한 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-post-on-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); 
      } 
     } 
    } 
} 

이는 "하드"캡을 방지 16ms이므로 필요한 시간이 경과하면 "대기"루프에 들어 가지 않습니다. 게시 된 코드를 고려하는 것도

, 몇 가지 참고 사항 :

먼저, (A PictureBox, Button, TextBox 등 같은) 모든 Windows 폼 요소를 사용하지 않고, 대신 그리는 경우 모든 요소 자아 (예 : Graphics.DrawLine 등을 호출하면) Application.DoEvents에 전화 할 필요가 없습니다. 이렇게하면 호출하는 스레드가 다른 모든 Windows Forms 메시지가 처리 될 때까지 대기하므로 렌더링 루프가 느려집니다. 실제로 Application.DoEvents으로 전화해야하는 경우 Render() 다음에 전화를 걸면 프레임 제한 시간에 해당 기능 호출 시간을 포함시키는 것이 좋습니다.

마지막으로, Windows 시스템은, 기회가 Sleep 실제로 이상 잠을 것입니다 비 실시간에 approximately 20 milliseconds 아무것도 미만의 Thread.Sleep 인해 Windows 시스템에서 스레드 전용 타임 슬라이스를 지정할 때. 따라서 Thread.Sleep(1)일 수 있습니다.은 1 밀리 초 동안 잠시 대기합니다. 또는 6 밀리 초 동안 잠자기 상태 일 수 있습니다. 시간 제한이 이미 14 밀리 초이면 6 밀리 초가 총 시간을 20 밀리 초 이상으로 늘리므로 프레임 속도가 느려집니다.

0 밀리 초의 대기 시간을 지정하면 호출 스레드의 시간 조각 나머지는 실행 준비가 된 동일한 우선 순위의 다른 스레드로 전달되지 않습니다. 다른 스레드가 준비되어 있지 않으면 호출 스레드가 계속됩니다 (0-1 밀리 초 대기, 6+). Thread.Yield을 사용할 수도 있지만 커널 수준에서는 Sleep과 많이 다릅니다.

희망이 도움이 될 수 있습니다.