質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.59%

C# 秒間60回の処理を行うタイマーが思ったように動作しません。

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 3,061

gucha

score 54

60fpsの処理を実現させるために「System.Environment.TickCount」を使ったタイマー処理を試したのですが上手く動作しなかったので知恵をお貸しください。
コードはこちらのサイトで紹介されているものとほぼ変わりません。

コード

<Grid>
    <Button Content="start" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
</Grid>
private void Button_Click(object sender, RoutedEventArgs e)
{
    double nextframe = (double)System.Environment.TickCount;
    float wait = 1000f / 60f;

    // 時間差確認用
    double diffTime = 0;

    while (true)
    {
        if ((double)System.Environment.TickCount >= nextframe)
        {
            // 現在の時刻を取得
            double nowtime = (double)System.Environment.TickCount;
            // 時間差
            double diff = nowtime - diffTime;
            // 更新
            diffTime = nowtime;
            nextframe += wait;

            Console.WriteLine("diff:" + diff + " now:" + nowtime + " nextframe:" + nextframe);
        }
    }
}

 
実行した結果の一部
diff:16 now:710521281 nextframe:710521295.333277
diff:15 now:710521296 nextframe:710521311.999943
diff:16 now:710521312 nextframe:710521328.666609
diff:31 now:710521343 nextframe:710521345.333275
diff:16 now:710521359 nextframe:710521361.999941
diff:16 now:710521375 nextframe:710521378.666607
diff:15 now:710521390 nextframe:710521395.333273
diff:16 now:710521406 nextframe:710521411.999939
diff:15 now:710521421 nextframe:710521428.666605
diff:16 now:710521437 nextframe:710521445.333271
diff:16 now:710521453 nextframe:710521461.999937
diff:15 now:710521468 nextframe:710521478.666603
diff:16 now:710521484 nextframe:710521495.333269
diff:16 now:710521500 nextframe:710521511.999935
diff:15 now:710521515 nextframe:710521528.666601
diff:16 now:710521531 nextframe:710521545.333267
diff:15 now:710521546 nextframe:710521561.999933
diff:16 now:710521562 nextframe:710521578.666599
diff:31 now:710521593 nextframe:710521595.333265
diff:16 now:710521609 nextframe:710521611.999931
diff:16 now:710521625 nextframe:710521628.666597

このような結果が得られました。
大体が1/60秒の周期で処理できているのですが、ところどころで1/60秒の倍ほどの間隔になってしまいます。スキップの指定はどれも1000f/60f間隔で加算できているのでこれはコードではなく環境の問題でしょうか?

原因と対処法があれば教えて頂きたいです。


追記

Stopwatchを使用したコードを考えてみました。
上手く機能しているように思いますが間違いや注意点などがあれば教えてください。

Stopwatch stopwatch = new Stopwatch();
private void Button_Click(object sender, RoutedEventArgs e)
{
    // 1/60秒の間隔
    // コメントにて指摘されたので修正
    // int interval = 166667;
    float interval = 1f / 60f * Stopwatch.Frequency;

    while (true)
    {
        if (stopwatch.ElapsedTicks >= interval)
        {
            // 指定した間隔を超えた時の処理
            Console.WriteLine(stopwatch.ElapsedMilliseconds);
            stopwatch.Restart();
        }
        else
        {
            // 指定した間隔未満だった時の処理 Stopwatchを再開
            stopwatch.Start();
        }
    }
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

TickCount は確かに1msの分解能はありますが、その実、時間的精度はあんましよろしくありません

C# 経過時間取得,タイマー

なので、こういう用途で使用する場合には、タイマを選ぶ必要があります

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/11/12 12:22

    ElapsedMillisecondsやElapsedTicksを読むとその時点でStopwatchが停止してしまうのでStartで再開させています。Restartでリセットして再開です。
    停止させずに読む方法が分からないのでこのような形にしました・・・。

    PerformanceCounterも環境依存で結構変わってしまう可能性があるのですね。これが最適かは分かりませんが狙っていた通りの動作が確認できました。解答ありがとうございました。

    キャンセル

  • 2018/11/12 12:40

    intervalに用いる値はStopwatch.Frequencyから計算されたほうがよろしいかと思います。
    手元のPC2台で比較したところ値が異なっていました。

    キャンセル

  • 2018/11/13 12:05

    教えて頂きありがとうございます。
    float interval = 1f / 60f * Stopwatch.Frequency;
    としました。こちらで問題ないでしょうか?

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.59%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る