2010-04-03 46 views
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应该相应地更新。另外,我打算在未来支持多人游戏,以防对游戏循环的设计产生影响。

有关如何实现此操作的任何提示或示例(除了指向文章的链接)?

回答

2

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

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

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

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

+0

对不起,我忘了提及我只关心在Xbox 360上运行,这意味着我将无法访问P/Invoke,并且我不需要担心系统何时需要绘制,因为我可以随时画画。 'Clock'类已经通过使用'Stopwatch.GetTimestamp()'准确计时。我的问题是关于如何构建固定更新循环以及如何跟踪流逝的“游戏/虚拟时间”。我认为我有一个相当好的理解,但我希望有一些建议,以防万一有更好的方法来做到这一点。不过谢谢你的回答! – 2010-04-04 14:50:02