如何为我的游戏获得更好的定时事件?

时间:2017-05-05 10:16:18

标签: c# wpf performance timer

我编写了一个普通的调度程序计时器方法,用于在WPF中创建游戏循环。我注意到,如果将它设置为比200毫秒更短的间隔,它就不能正确赶上。

我将秒打印到屏幕上(参见下面的代码)并将其与我的手表进行比较。设置为500毫秒,没关系,但是如果我把它设置得低得多,就会有很大的差异。我尝试了10毫秒的设置,这意味着屏幕上的时间在(实际)分钟内仅通过38秒! (请注意,我的所有游戏引擎代码在测试期间都被删除了,所以它只是被调用的定时器循环。另外,如果我从VS运行代码或者在Debug中运行exe文件也没关系文件夹)。

请注意,我创建的游戏运行顺畅,只是我的(标准)Every_Tick方法在正确的时间没有被调用。这反过来意味着我的游戏将在更快的计算机上运行得更快。

那么如何保持正确的时间跟踪并确保Every_Tick方法同时触发,与所使用的计算机(或手机)无关?也就是说,我宁愿对游戏对象的数量,碰撞检测精度等进行限制,但要准时,而不是尽可能快地进行。换句话说,如果我将定时器增量值设置为50ms(我认为这是合理的,因为这意味着每秒20次),我真的希望游戏每秒更新20次。

如果有可能避免它,我真的不想进入线程等,因为游戏本身现在运行良好。我只是希望他们以相同的速度回放。

我在How to control frame rate in WPF by using dispatcher timer accurately?查看了一些很棒的回复,但这仍然没有回答我的问题:如何让我的游戏以相同的速度运行,无论(现代)计算机/手机和无论是WPF / UWP还是别的什么?

或者这是不可能以一种相当简单的方式做到的,我应该接受游戏速度取决于所使用的计算机?

谢谢!

代码:

    public void StartTimer()
    {
        //This variable is used to get to the controls (labels etc) of the MainWindow (WPF)
        MainWindow mainWin = System.Windows.Application.Current.Windows.Cast<System.Windows.Window>().FirstOrDefault(window => window is MainWindow) as MainWindow;

        time = TimeSpan.FromSeconds(0);

        //What the code below does is this:
        //For each 10 ms, call the different methods. Then add 10 ms to the current time.

        timer = new DispatcherTimer(new TimeSpan(0, 0, 0, 0, 10), DispatcherPriority.Normal, delegate
        {
            if (runGame == false) return; //only go on if not in pause mode
            mainWin.txtInfo.Text = time.ToString("mm\\:ss");//Shows the timer in a textbox, only showing minutes and seconds.


            //Collision code etc removed during the test

            time = time.Add(TimeSpan.FromMilliseconds(10)); //adds a specified time to the current time
        }, System.Windows.Application.Current.Dispatcher);
    }

请注意,上面的代码是为了测试目的而添加的。原始代码(面临同样的问题)看起来像这样:

    public void StartTimer()
    {
        //A note on the dispatcherTimer http://www.wpf-tutorial.com/misc/dispatchertimer/
        var timer = new DispatcherTimer();
        timer.Interval = new TimeSpan(0, 0, 0, 0, 10); // Each every n milliseconds (set low to avoid flicker)
        timer.Tick += EachTick;
        timer.Start();
    }

    // A testing counter
    int counter = 0;

    // Raised every tick while the DispatcherTimer is active.
     private void EachTick(object sender, object e)
    { etc

1 个答案:

答案 0 :(得分:0)

内置计时器并不十分准确。使用此代码段。我多次使用这个计时器。这个计时器非常准确。感谢John

public class AccurateTimer
    {
        private delegate void TimerEventDel(int id, int msg, IntPtr user, int dw1, int dw2);
        private const int TIME_PERIODIC = 1;
        private const int EVENT_TYPE = TIME_PERIODIC;
        [DllImport("winmm.dll")]
        private static extern int timeBeginPeriod(int msec);
        [DllImport("winmm.dll")]
        private static extern int timeEndPeriod(int msec);
        [DllImport("winmm.dll")]
        private static extern int timeSetEvent(int delay, int resolution, TimerEventDel handler, IntPtr user, int eventType);

        private readonly int _mTimerId;

        public AccurateTimer(int delay)
        {
            timeBeginPeriod(1);
            _mTimerId = timeSetEvent(delay, 0, TimerTick, IntPtr.Zero, EVENT_TYPE);
        }

        public void Stop()
        {
            timeEndPeriod(1);
            System.Threading.Thread.Sleep(100);// Ensure callbacks are drained
        }

        private void TimerTick(int id, int msg, IntPtr user, int dw1, int dw2)
        {
            Console.WriteLine("Tick " + DateTime.Now.TimeOfDay.TotalMilliseconds);
        }
    }