http://blog.csdn.net/hitachi_ht/article/details/38150955
经过大量前辈的实践证明,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;
- }
- [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);
- 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);
- }
- void GameLoop (double ElapsedTime) {
- }
- TimeController timeController;
- timeController = new TimeController(GameLoop);
就完成了。
这些东西在网上比较难找,所以特意记下来。