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 o开发者_如何学Cf 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)?
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()
.
精彩评论