CheatCat's picture

Timer?

How I make a timer?


Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Soundbomber's picture

In VB.NET (not sure about c#)

Private oStopWatch As Stopwatch = New Stopwatch()
 
Private Sub ctlSketch_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
 
        AddHandler Application.Idle, AddressOf Me.Application_Idle
        Me.oStopWatch.Start()
 
End Sub
 
Private Sub Application_Idle(ByVal sender As Object, ByVal e As EventArgs)
 
        Me.oStopWatch.Stop()    ' We've measured everything since last Idle run
        Dim dMilliseconds As Double = Me.oStopWatch.Elapsed.TotalMilliseconds
        Me.oStopWatch.Reset()   ' Reset stopwatch
        Me.oStopWatch.Start()   ' Restart stopwatch
 
End Sub
the Fiddler's picture

There are two main approaches to timers:

  • Polling, where you continuously check whether the time period has passed. You can use System.Diagnostics.Stopwatch or System.DateTime.Now to create such a timer.
  • Event-based, where you register an event handler to be called at some future time. You can use System.Threading.Timer to register such a callback.

First, you need to decide what kind of accuracy you need:

  • Stopwatch provides sub-millisecond precision, but may drift over larger time spans.
  • DateTime.Now and Threading.Timer are stable over larger time spans, but lose accuracy under tens of milliseconds.

Use a Stopwatch for accurate measurements over a few seconds. Use DateTime.Now as a wall clock (for example, to measure total gameplay time). Use Threading.Timer to schedule an event to be fired in the future (just take care that the event is fired in a new thread, so don't write OpenGL code directly inside the handler).

objarni's picture

CheatCat: what is it that you want to do?

Dinberg's picture

Am I right in thinking Stopwatch is syncronous and Timer calls an asyncronous thread aswell? Or can stopwatch be used to invoke a separate thread on a delegate?

objarni's picture

Stopwatch is synchronous, no threads involved AFAIK.

Timer is used in WinForms development to trigger a continous flow of events. It has no precision whatsoever, think 10th of a second. Over time it lags too; if you set it to trigger an event once a second it will be off-beat in a minute if your OS is doing anything fun in the background.

Again; what is it that you are trying to do in your application? My guess is that you are doing animation of the player jumping (reading other threads).

If I'm right, you can use GameWindows built-in delta-time measurements. In UpdateFrame(double deltaTime) deltaTime is a measure of how long time has passed since the last call to UpdateFrame(). I'll leave the details to you (don't know them by heart).

the Fiddler's picture

The 2.0 BCL provides three event-based and two polling-based timer implementations.

Event-based:

  • System.Windows.Forms.Timer: objarni covered this one. Just stay away (it won't even work with the GameWindow).
  • System.Timers.Timer: accurate, asynchronous (the event is raised in a background thread). Appears to be relatively heavy, but has more features than other timers.
  • System.Threading.Timer: accurate, lightweight, asynchronous (the event is raised in a ThreadPool thread).

Verdict: use System.Threading.Timer, unless you need more features (in that case, check out System.Timers.Timer). Avoid System.Windows.Forms.Timer, unless you are writing a GUI application.

Polling-based:

  • System.Diagnostics.Stopwatch: Accurate, precise, suitable for short time-periods.
  • System.DateTime.Now: stable over large time-periods.

Verdict: use Stopwatch if you need sub-second precision; use DateTime.Now otherwise.

You can use "e.Time" in GameWindow.UpdateFrame and RenderFrame to get the elapsed period since the last UpdateFrame/RenderFrame event respectively. This is based on Stopwatch, hence accurate, but don't use it to measure large time spans.

If I recall correctly, CheatCat wanted a timer to control animation. Solution: use e.Time from UpdateFrame event:

protected override void UpdateFrame(FrameEventArgs e)
{
    // Simple jump calculation
    if (Keyboard[Key.Up])
        Player.Velocity = new Vector(0, 20, 0);  // 20 m / s, direction: up
 
    // Simple movement calculation. Can get numerically unstable over time,
    // though it's generally not a problem in practice.
    Player.Velocity += Gravity * e.Time;     // Gravity is defined as Vector(0, -10, 0) m / s^2
    Player.Position += Player.Velocity * e.Time;
}

By playing around with the values, you can get nice results with very little work.

kanato's picture

I would avoid using DateTime.Now. I recall profiling a while back and noticing that DateTime.Now seems to box some ints, so several calls to it in each frame can generate quite a bit of garbage.