游戏循环和时间跟踪

时间:2010-04-03 03:03:56

标签: c# timing game-loop

也许我只是个白痴,但我一直在努力实现一整天的游戏循环,而不是点击。我几乎可以在Google上找到每篇文章,但问题是它们都使用不同的计时机制,这使得它们难以应用于我的特定情况(有些使用毫秒,其他使用滴答等)。

基本上,我有一个Clock对象,每次游戏循环执行时都会更新。

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);
    }
}

我的大部分内容都基于XNA GameClock,但它大大简化了。然后,我有一个Time类,其中包含UpdateDraw方法需要知道的各种时间。

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;
    }
}

我的主要类保留Time的单个实例,它应该在游戏循环期间不断更新。到目前为止,我有这个:

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

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

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

时间等级的实时属性变得很棒。现在我想得到一个正确的更新/绘制循环工作,以便状态每帧更新一次可变的次数,但是在固定的时间步长。同时,Time.TotalVirtualTimeTime.ElapsedVirtualTime应相应更新。另外,我打算在未来支持多人游戏,以免对游戏循环的设计产生任何影响。

关于我如何实现这一点的任何提示或示例(除了文章的链接)?

1 个答案:

答案 0 :(得分:2)

主要用于XNA的方法是以固定费率调用Update(),并尽可能多地调用Draw(),直到达到某个限制。在Update()方法中,您只需更新变量以反映新时刻的世界,并且在调用Draw()时,您只能将其绘制到屏幕上。

要让Update()以固定费率运行,您可能希望使用计时器或使用更精确的计时:

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

然后你可以使用另一个(较慢的)计时器,它在你用来绘制你的游戏(画布)的对象上调用Invalidate()。在画布'Paint-event中,您调用Draw()。这样,每当系统认为必要时(当它使画布无效时),或者在您调用Invalidate()后有机会这样做时,您的世界就会被绘制。