2010-04-03 99 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