2

也许我只是个白痴,但我整天都在尝试实现一个游戏循环,但它只是没有点击。我从字面上阅读了我在 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应相应更新。此外,我打算在未来支持多人游戏,以防对游戏循环的设计产生任何影响。

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

4

1 回答 1

2

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

Update()以固定速率运行,您可能需要使用计时器或更准确的计时:

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

然后,您可以使用另一个(较慢)计时器来调用Invalidate()您用来绘制游戏的对象(画布)。在画布的 Paint-event 中,您调用Draw(). 这样,每次系统认为有必要时(当它使您的画布无效时)或一旦您调用Invalidate().

于 2010-04-04T11:13:01.297 回答