【问题标题】:How to reduce tick rate of winforms timer?如何降低winforms计时器的滴答率?
【发布时间】:2018-12-05 11:22:07
【问题描述】:

我正在编写一个使用计时器完成动画的简单游戏。计时器速率最初设置为 200,但是对于每 1000 点玩家获得我希望计时器变得更快,所以我想我可以减少间隔

if (score > 0 && score % 1000 == 0)
     {
         GameTimer.Interval -= 20;
     }

但是当我达到 1000 分时,winform 崩溃并在上面给出的行出现以下错误:

System.ArgumentOutOfRangeException:“值“0”不是间隔的有效值。间隔必须大于 0。 参数名称:间隔

如何正确降低间隔率? (或通过任何其他方式让我的程序运行得更快)

编辑:上面给出的代码段被放置在tick事件中,导致if语句执行多次

【问题讨论】:

  • 请注意,减小Interval 会增加速率,因为间隔以毫秒为单位;这是你想要的吗?
  • @Bizhan 我很确定它最初设置为 200。我改变它的方法是从 Form1.cs[Design] 页面中的计时器属性菜单中编辑初始值(100)
  • 是的,我明白了,并删除了我的评论。请看下面我的回答
  • @Ach113 我不知道整个实现,但我想如果玩家有 1000 分并且您运行此代码几次,您可能会遇到问题。所以,运行时要小心。
  • 检查Interval是否-= 20。

标签: c# winforms


【解决方案1】:

错误表示Interval值已达到零。

所以这些行会被执行几次,直到它崩溃:

 if (score > 0 && score % 1000 == 0)
 {
     GameTimer.Interval -= 20;
 }

那是因为在计时器通过一次条件后,每个时间间隔都满足条件。

在定时器代码之外定义你的逻辑,你会没事的:

 void Score(int value){

      score += value;
      if (score <= 0) return;

      if(score % 1000 == 0)
      {
          GameTimer.Interval -= 20;
          //if(GameTimer.Interval <= 0) I suppose level is already finished...
      }
 }

已编辑

mjwills 指出这个问题,间隔仍然可能达到零。因此,您必须以消除这种风险的方式编写代码。

在这种情况下,非线性减少更有意义:

 void Score(int value){

      score += value;
      if (score <= 0) return;

      if(score % 1000 == 0)
      {
          GameTimer.Interval *= .9f;
          if(GameTimer.Interval <= 0) GameTimer.Interval = 1;
      }
 }

【讨论】:

  • Interval 是否仍有可能达到 0(尽管速度较慢)?
  • @mjwills 是的,但我想 OP 在设置这些幻数时会考虑到限制。但感谢您指出这一点
  • 我怀疑 OP 没有没有想到这一点(事实上,这不仅仅是一种怀疑 - 我们知道他们没有,因为这就是他们看到例外开始!)。因此,可能值得调整解决方案以保护他/她不被自己的脚射伤。 您可能希望在设置之前检查值,而不是之后。
  • @Ach113 如果我在这里有点偏离主题,请原谅我,但是(因为这是一场游戏)当你比较区间 200->180 和 40->20 时,速度的突然变化是剧烈的在最后一个速度突然加倍的地方。但是对于非线性过渡,速度的变化总是有相同的感觉。
  • @Bizhan 明白了,没想到,再次感谢!
【解决方案2】:

滴答率不能小于或等于 0。

您可以简单地添加一个 if 语句来检查:

if (GameTimer.Interval <= 20) {
    GameTimer.Interval = 1;
} else {
    GameTimer.Interval -= 20;
}

但是,这意味着计时器间隔将在达到某个分数后达到限制。此外,屏幕无法快速更新(每秒 1000 次)。您应该将帧速率保持在 30fps。

因此,为了让动画出现得更快,每秒做更大比例的动画。例如,要向右移动 1000 像素,不要每 1/1000 秒移动 1 像素。相反,每 1/20 秒移动 50 个像素。

来自您的评论:

问题是我不明白为什么间隔低于零,if 语句只执行一次,它立即给我这个错误。

然后你不止一次地执行 if 语句。我的猜测是您正在计时器滴答事件处理程序中运行它。一旦您的分数达到 1000 的倍数,则每次计时器滴答时都会运行该 if 语句,直到您的分数发生变化。

要解决这个问题,您可以将代码放在分数的设​​置器中。

【讨论】:

    【解决方案3】:

    计时器间隔不断减少,直到它达到零“0”,这是你的错误

    你可以使用

    int x = (score/1000)*20  
    if (x < 200)
        GameTimer.Interval = (200 - x);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多