La Application.Run
llamada impulsa su bomba de mensajes de Windows, que en última instancia es lo que alimenta todos los eventos que puede conectarForm
clase (y otros). Para crear un bucle de juego en este ecosistema, desea escuchar cuándo la bomba de mensajes de la aplicación está vacía y, mientras permanece vacía, realice los pasos típicos de "estado de entrada del proceso, actualice la lógica del juego, renderice la escena" del bucle de juego prototípico .
El Application.Idle
evento se dispara una vez cada vez que se vacía la cola de mensajes de la aplicación y la aplicación está pasando a un estado inactivo. Puede enganchar el evento en el constructor de su formulario principal:
class MainForm : Form {
public MainForm () {
Application.Idle += HandleApplicationIdle;
}
void HandleApplicationIdle (object sender, EventArgs e) {
//TODO: Implement me.
}
}
A continuación, debe poder determinar si la aplicación aún está inactiva. El Idle
evento solo se dispara una vez, cuando la aplicación queda inactiva. No se dispara nuevamente hasta que un mensaje ingresa a la cola y luego la cola se vacía nuevamente. Windows Forms no expone un método para consultar el estado de la cola de mensajes, pero puede usar los servicios de invocación de plataforma para delegar la consulta a una función nativa de Win32 que pueda responder esa pregunta . La declaración de importación PeekMessage
y sus tipos de soporte se ven así:
[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
básicamente le permite mirar el siguiente mensaje en la cola; devuelve verdadero si existe, falso de lo contrario. Para los propósitos de este problema, ninguno de los parámetros es particularmente relevante: lo que importa es solo el valor de retorno. Esto le permite escribir una función que le indica si la aplicación aún está inactiva (es decir, todavía no hay mensajes en la cola):
bool IsApplicationIdle () {
NativeMessage result;
return PeekMessage(out result, IntPtr.Zero, (uint)0, (uint)0, (uint)0) == 0;
}
Ahora tienes todo lo que necesitas para escribir tu ciclo de juego completo:
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);
}
Además, este enfoque coincide lo más cerca posible (con una dependencia mínima de P / Invoke) con el bucle canónico del juego nativo de Windows, que se ve así:
while (!done) {
if (PeekMessage(&message, window, 0, 0, PM_REMOVE)){
TranslateMessage(&message);
DispatchMessage(&message);
}
else {
Update();
Render();
}
}