Direct2D教程:在C#的WinForm环境下创建Gameloop

发表于2018-05-31
评论0 2.6k浏览
经过大量前辈的实践证明,C#中Timer们的精度都无法达到60fps的需求。这一点可以做个实验,用2个Timer,一个1s,另一个0.01667s,然后后面timer的tick时给count+1,前面的每秒统计一下后面有几个+1,就会发现可能每秒只有大概30次左右。

关于比较好的计时系统google上面也有,就是利用这个性能计数器,计量的经度就能到很高了。
[System.Security.SuppressUnmanagedCodeSecurity]  
[DllImport("kernel32")]  
private static extern bool QueryPerformanceFrequency (ref long PerformanceFrequency);  
[System.Security.SuppressUnmanagedCodeSecurity]  
[DllImport("kernel32")]  
private static extern bool QueryPerformanceCounter (ref long PerformanceCounter); 

为了把这个融入到Gameloop里面,我写了个类用来计时
public class PreciseTimer {  
      [System.Security.SuppressUnmanagedCodeSecurity]  
      [DllImport("kernel32")]  
      private static extern bool QueryPerformanceFrequency (ref long PerformanceFrequency);  
      [System.Security.SuppressUnmanagedCodeSecurity]  
      [DllImport("kernel32")]  
      private static extern bool QueryPerformanceCounter (ref long PerformanceCounter);  
      long _tickPerSecond = 0;  
      long _previousElapsedTime = 0;  
      public PreciseTimer () {  
            QueryPerformanceFrequency(ref _tickPerSecond);  
            GetElapsedTime();  
      }  
      public double GetElapsedTime () {  
            long Time = 0;  
            QueryPerformanceCounter(ref Time);  
            double ElapsedTime = (double)(Time - _previousElapsedTime) / (double)_tickPerSecond;  
            _previousElapsedTime = Time;  
            return ElapsedTime;  
      }  
}  

这样就可以得到一个相对准确的秒表了。
然后,我们需要windows的消息处理机制,这里我们使用了C里面的Message。
[StructLayout(LayoutKind.Sequential)]  
public struct Message {  
      public IntPtr hWnd;  
      public Int32 Msg;  
      public IntPtr wParam;  
      public IntPtr lParam;  
      public uint time;  
      public System.Drawing.Point P;  
}  

并且我们需要C里面的PeekMessage函数。
[System.Security.SuppressUnmanagedCodeSecurity]  
[DllImport("User32.dll", CharSet = CharSet.Auto)]  
public static extern bool PeekMessage (  
      out Message Msg,  
      IntPtr hWnd,  
      uint messageFilterMin,  
      uint messageFilterMax,  
      uint flags);  

然后利用这些东西,我们就拼凑出了一个类,起名叫做TimeController。
PreciseTimer _preciseTimer = new PreciseTimer();  
public delegate void LoopCallBack (double ElapsedTime);  
LoopCallBack _loopCallBack;  
public TimeController (LoopCallBack CallBack) {  
            _loopCallBack = CallBack;  
            Application.Idle += new EventHandler(OnApplicationEnterIdle);  
}  
private void OnApplicationEnterIdle (object sender, EventArgs e) {  
            while (IsAppStillIdle())  
                  _loopCallBack(_preciseTimer.GetElapsedTime());  
}  
private bool IsAppStillIdle () {  
            Message Msg;  
            return !PeekMessage(out Msg, IntPtr.Zero, 0, 0, 0);  
}  

然后我们只需要在Form1.cs里面添加一个Gameloop函数
void GameLoop (double ElapsedTime) {  
}

最后定义出来timeController。
TimeController timeController;  

并且将Gameloop放进去
timeController = new TimeController(GameLoop);  
就完成了。
来自:https://blog.csdn.net/hitachi_ht/article/details/38150955


如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引