L’ Application.Run
appel entraîne votre pompe de messages Windows, qui alimente en définitive tous les événements que vous pouvez raccrocher auForm
classe (et à d'autres). Pour créer une boucle de jeu dans cet écosystème, vous souhaitez écouter lorsque la pompe à messages de l'application est vide et pendant qu'il reste vide, effectuez les étapes typiques "État d'entrée du processus, mise à jour de la logique de jeu, rendu de la scène" de la boucle de jeu prototypique. .
L' Application.Idle
événement est déclenché une fois à chaque fois que la file de messages de l'application est vidée et que l'application passe à un état inactif. Vous pouvez accrocher l'événement au constructeur de votre formulaire principal:
class MainForm : Form {
public MainForm () {
Application.Idle += HandleApplicationIdle;
}
void HandleApplicationIdle (object sender, EventArgs e) {
//TODO: Implement me.
}
}
Ensuite, vous devez être capable de déterminer si l'application est toujours inactive. L' Idle
événement ne se déclenche qu'une seule fois, lorsque l'application devient inactive. Il ne se déclenche plus jusqu'à ce qu'un message arrive dans la file d'attente, puis la file se vide à nouveau. Windows Forms n'expose pas de méthode pour interroger l'état de la file d'attente de messages, mais vous pouvez utiliser les services d'appel de plate-forme pour déléguer la requête à une fonction Win32 native qui peut répondre à cette question . La déclaration d'importation de PeekMessage
et ses types de support se présentent comme suit:
[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
vous permet essentiellement de regarder le message suivant dans la file d'attente; il retourne vrai s'il en existe un, faux sinon. Pour les besoins de ce problème, aucun paramètre n'est particulièrement pertinent: seule la valeur de retour compte. Cela vous permet d'écrire une fonction qui vous indique si l'application est toujours inactive (c'est-à-dire qu'il n'y a toujours aucun message dans la file d'attente):
bool IsApplicationIdle () {
NativeMessage result;
return PeekMessage(out result, IntPtr.Zero, (uint)0, (uint)0, (uint)0) == 0;
}
Vous avez maintenant tout ce dont vous avez besoin pour écrire votre boucle de jeu complète:
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);
}
De plus, cette approche correspond le plus possible (avec une dépendance minimale à P / Invoke) à la boucle de jeu canonique native de Windows, qui ressemble à ceci :
while (!done) {
if (PeekMessage(&message, window, 0, 0, PM_REMOVE)){
TranslateMessage(&message);
DispatchMessage(&message);
}
else {
Update();
Render();
}
}