如何在WPF中准确使用调度定时器来控制帧速率
本文关键字:定时器 调度 控制 帧速率 控制帧 WPF | 更新日期: 2023-09-27 18:01:05
当我试图使用System.Windows.Threading.DispatcherTimer实例控制WPF中的帧速率时,遇到了一个问题。
为了尝试DispatcherTimer的有效性,我创建了一个简单的WPF演示,其中有一个文本框和一个按钮。单击该按钮时,DispatcherTimer实例开始根据文本框中作为间隔的双数进行计时,StopWatch同时启动,计数器变量在每个DispatcherTimer计时时增加1。当StopWatch.ElaspedMilliSeconds>1000(超过1秒(时,计时器停止计时,秒表也会重置,此时会弹出一个显示计数器值的消息框。
因此,如果我输入33.3(1000/30(,计数器值应该在30左右。但结果是在20左右。我请求帮助是否有人可以帮助检查下面我的源代码中的问题。提前谢谢。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace TimerDemo
{
public partial class MainWindow : Window
{
private System.Windows.Threading.DispatcherTimer _timer = new System.Windows.Threading.DispatcherTimer();
public MainWindow()
{
InitializeComponent();
double ticks = 0L;
System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
int frameCount = 0;
//There is a textbox "txtTicks" which accepts a millisecond value
//And a button "btn", by clicking the button the dispatchertimer &
//stopwatcher are started.
_timer.Tick += (sender, e) =>
{
frameCount++;
System.Diagnostics.Debug.WriteLine(watch.ElapsedMilliseconds);
if (watch.ElapsedMilliseconds > 1000)
{
_timer.Stop();
watch.Reset();
MessageBox.Show(string.Format("Already 1 second! FrameCount: {0}", frameCount));
frameCount = 0;
}
};
this.btn.Click += (sender, e) =>
{
double.TryParse(this.txtTicks.Text, out ticks);
if (ticks != 0.0)
{
_timer.Interval = TimeSpan.FromMilliseconds(ticks);
}
_timer.Start();
watch.Start();
};
}
}
}
运行结果如下(堆栈溢出的新手,还不能上传图像(:
https://i.stack.imgur.com/u6W2s.png
由于WPF(和大多数其他渲染引擎(渲染每一帧所需的时间并不相等,而且不同的计算可能会进一步延迟帧之间的间隔,因此使用CompositionTarget.Rendering
来"计时"渲染间隔是正确的,但您仍然可以使用"挂钟"计时器以规则、严格控制的间隔更新游戏。
在优秀的书籍"游戏编程模式"(在线免费提供(中,你可以找到非常有用的游戏循环模式。
在其完整形式中,这是您将放在CompositionTarget.Rendering
事件的处理程序中的内容(以伪代码形式(:
双电流=getCurrentTime((;双倍运行时间=当前-以前;previor=当前;lag+=经过;processInput((;而(滞后>=MS_PER_UPDATE({update((;滞后-=MS_PER_UPDATE;}render((;
例如,在C#中,可以通过调用DateTime.Now
或使用Stopwatch.Elapsed
来实现getCurrentTime()
。