views:

263

answers:

1

Maybe I'm just an idiot, but I've been trying to implement a game loop all day and it's just not clicking. I've read literally every article I could find on Google, but the problem is that they all use different timing mechanisms, which makes them difficult to apply to my particular situation (some use milliseconds, other use ticks, etc).

Basically, I have a Clock object that updates each time the game loop executes.

internal class Clock {
    public static long Timestamp {
        get { return Stopwatch.GetTimestamp(); }
    }

    public static long Frequency {
        get { return Stopwatch.Frequency; }
    }

    private long _startTime;
    private long _lastTime;
    private TimeSpan _totalTime;
    private TimeSpan _elapsedTime;

    /// <summary>
    /// The amount of time that has passed since the first step.
    /// </summary>
    public TimeSpan TotalTime {
        get { return _totalTime; }
    }

    /// <summary>
    /// The amount of time that has passed since the last step.
    /// </summary>
    public TimeSpan ElapsedTime {
        get { return _elapsedTime; }
    }

    public Clock() {
        Reset();
    }

    public void Reset() {
        _startTime = Timestamp;
        _lastTime = 0;
        _totalTime = TimeSpan.Zero;
        _elapsedTime = TimeSpan.Zero;
    }

    public void Tick() {
        long currentTime = Timestamp;

        if (_lastTime == 0)
            _lastTime = currentTime;

        _totalTime = TimestampToTimeSpan(currentTime - _startTime);
        _elapsedTime = TimestampToTimeSpan(currentTime - _lastTime);
        _lastTime = currentTime;
    }

    public static TimeSpan TimestampToTimeSpan(long timestamp) {
        return TimeSpan.FromTicks(
            (timestamp * TimeSpan.TicksPerSecond) / Frequency);
    }
}

I based most of that on the XNA GameClock, but it's greatly simplified. Then, I have a Time class which holds various times that the Update and Draw methods need to know.

public class Time {
    public TimeSpan ElapsedVirtualTime { get; internal set; }
    public TimeSpan ElapsedRealTime { get; internal set; }
    public TimeSpan TotalVirtualTime { get; internal set; }
    public TimeSpan TotalRealTime { get; internal set; }

    internal Time() { }

    internal Time(TimeSpan elapsedVirtualTime, TimeSpan elapsedRealTime,
            TimeSpan totalVirutalTime, TimeSpan totalRealTime) {
        ElapsedVirtualTime = elapsedVirtualTime;
        ElapsedRealTime = elapsedRealTime;
        TotalVirtualTime = totalVirutalTime;
        TotalRealTime = totalRealTime;
    }
}

My main class keeps a single instance of Time, which it should constantly update during the game loop. So far, I have this:

private static void Loop() {
    do {
        Clock.Tick();

        Time.TotalRealTime = Clock.TotalTime;
        Time.ElapsedRealTime = Clock.ElapsedTime;

        InternalUpdate(Time);
        InternalDraw(Time);
    } while (!_exitRequested);
}

The real time properties of the time class turn out great. Now I'd like to get a proper update/draw loop working so that the state is updated a variable number of times per frame, but at a fixed timestep. At the same time, the Time.TotalVirtualTime and Time.ElapsedVirtualTime should be updated accordingly. In addition, I intend for this to support multiplayer in the future, in case that makes any difference to the design of the game loop.

Any tips or examples on how I could go about implementing this (aside from links to articles)?

+1  A: 

The approach mainly used in XNA is to call Update() at some fixed rate, and call Draw() as much as it can, up to some limit. In the Update() method, you'd only update variables to reflect the world at the new moment in time, and when Draw() is called, you only draw it to the screen.

To get Update() to run at a fixed rate, you might want to use you timer or an even more accurate timing using:

[DllImport("kernel32.dll")]
public static extern long GetTickCount();

Then you could use another (slower) timer which calls Invalidate() on the object you use to paint your game (the canvas). In the canvas' Paint-event, you call Draw(). This way, your world gets drawn each time the system deems it necessary (when it invalidates your canvas) or as soon as it has the opportunity to do so once you called Invalidate().

Virtlink
Sorry, I forgot to mention that I'm only concerned with running on the Xbox 360, which means I won't have access to P/Invoke and I don't need to worry about when the system wants me to draw, because I can draw whenever I want to. The `Clock` class already has accurate timing by using `Stopwatch.GetTimestamp()`. My question is really about how I need to structure the fixed update loop and how I can track elapsed "game/virtual time". I think I have a pretty good understanding, but I'd like some suggestions just in case there's a better way to do it. Thanks for the answer, though!
David Brown