Der Application.Run
Aufruf steuert Ihre Windows-Nachrichtenpumpe. Dies ist letztendlich die Grundlage für alle Ereignisse, die Sie für die Form
Klasse (und für andere) festlegen können . Um eine Spieleschleife in diesem Ökosystem zu erstellen, möchten Sie abhören, wenn die Nachrichtenpumpe der Anwendung leer ist. Führen Sie die typischen Schritte der prototypischen Spieleschleife aus, während sie leer bleibt .
Das Application.Idle
Ereignis wird jedes Mal ausgelöst, wenn die Nachrichtenwarteschlange der Anwendung geleert wird und die Anwendung in einen Ruhezustand übergeht. Sie können das Ereignis in den Konstruktor Ihres Hauptformulars einbinden:
class MainForm : Form {
public MainForm () {
Application.Idle += HandleApplicationIdle;
}
void HandleApplicationIdle (object sender, EventArgs e) {
//TODO: Implement me.
}
}
Als Nächstes müssen Sie feststellen können, ob die Anwendung noch inaktiv ist. Das Idle
Ereignis löst nur einmal, wenn die Anwendung wird im Leerlauf. Es wird nicht erneut ausgelöst, bis eine Nachricht in der Warteschlange eingeht und die Warteschlange dann wieder geleert wird. Windows Forms stellt keine Methode zum Abfragen des Status der Nachrichtenwarteschlange zur Verfügung. Sie können jedoch Plattformaufrufdienste verwenden, um die Abfrage an eine systemeigene Win32-Funktion zu delegieren, die diese Frage beantworten kann . Die Einfuhranmeldung für PeekMessage
und ihre unterstützenden Typen sieht folgendermaßen aus:
[StructLayout(LayoutKind.Sequential)]
public struct NativeMessage
{
public IntPtr Handle;
public uint Message;
public IntPtr WParameter;
public IntPtr LParameter;
public uint Time;
public Point Location;
}
[DllImport("user32.dll")]
public static extern int PeekMessage(out NativeMessage message, IntPtr window, uint filterMin, uint filterMax, uint remove);
PeekMessage
Im Prinzip können Sie die nächste Nachricht in der Warteschlange anzeigen. es gibt true zurück, falls vorhanden, andernfalls false. Für die Zwecke dieses Problems ist keiner der Parameter besonders relevant: Nur der Rückgabewert ist von Bedeutung. Auf diese Weise können Sie eine Funktion schreiben, die angibt, ob die Anwendung noch inaktiv ist (dh, die Warteschlange enthält noch keine Nachrichten):
bool IsApplicationIdle () {
NativeMessage result;
return PeekMessage(out result, IntPtr.Zero, (uint)0, (uint)0, (uint)0) == 0;
}
Jetzt hast du alles, was du brauchst, um deine komplette Spieleschleife zu schreiben:
class MainForm : Form {
public MainForm () {
Application.Idle += HandleApplicationIdle;
}
void HandleApplicationIdle (object sender, EventArgs e) {
while(IsApplicationIdle()) {
Update();
Render();
}
}
void Update () {
// ...
}
void Render () {
// ...
}
[StructLayout(LayoutKind.Sequential)]
public struct NativeMessage
{
public IntPtr Handle;
public uint Message;
public IntPtr WParameter;
public IntPtr LParameter;
public uint Time;
public Point Location;
}
[DllImport("user32.dll")]
public static extern int PeekMessage(out NativeMessage message, IntPtr window, uint filterMin, uint filterMax, uint remove);
}
Darüber hinaus entspricht dieser Ansatz so genau wie möglich (mit minimaler Abhängigkeit von P / Invoke) der kanonischen systemeigenen Windows-Spieleschleife, die wie folgt aussieht:
while (!done) {
if (PeekMessage(&message, window, 0, 0, PM_REMOVE)){
TranslateMessage(&message);
DispatchMessage(&message);
}
else {
Update();
Render();
}
}