2009-03-25 7 views
6

Cada tutorial del juego y el marco del juego (incluso el más nuevo XNA Framework) comienzan con un ciclo interminable que tiene un equivalente de DoEvents() para evitar que el sistema operativo se bloquee.¿Mejores bucles de juego que bucle infinito + bloque?

Desde una perspectiva no basada en juegos, siento que este tipo de código huele bastante a funky.
¿No hay mejores alternativas?

--EDIT--
Una gran cantidad de respuestas decir que cada programa es básicamente un bucle. Es cierto, pero creo que el bucle debe ser realizado por su sistema operativo, no por usted. Solo el sistema operativo tiene toda la información que necesita para distribuir sus recursos de manera óptima. ¿O me estoy perdiendo un punto importante aquí?

+0

Sí, te estás perdiendo la importante distinción de que un juego no es un servicio del sistema operativo. – Hejazzman

Respuesta

5

Cada aplicación de Windows tiene en su centro un bucle que se ve algo como esto:

BOOL bRet; 

while((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) 
{ 
    if (bRet == -1) 
    { 
     // handle the error and possibly exit 
    } 
    else 
    { 
     TranslateMessage(&msg); 
     DispatchMessage(&msg); 
    } 
} 

Es el trabajo de la aplicación - no los system's operativos - para asegurarse de que los mensajes se envían. Como probablemente sepa, los primeros juegos de Windows usaban un método alternativo donde, en lugar de llamar a la función de bloqueo GetMessage, llamaban al PeekMessage, y luego llamaban al bucle de procesamiento principal del juego si no había ningún mensaje que manejar. Se utilizaron varias formas de retrasos para tratar de obtener una velocidad de fotogramas adecuada sin tomar 100% de CPU. Simplemente no había un temporizador lo suficientemente bueno para dar una velocidad de fotogramas suave.

Hoy en día, puede que no sea necesario escribir explícitamente un ciclo que llame al DoEvents. Es podría ser posible obtener una velocidad de fotogramas sin problemas mediante el uso de temporizadores de grupo de temporizador integrados (expuestos en .NET por System.Threading.Timer, y envuelto por System.Timers.Timer).

Como recuerdo, también hubo problemas para obtener eventos de mouse y teclado de manera oportuna. Utilizamos el acceso directo al teclado y al mouse en lugar de depender del bucle del mensaje, porque el bucle de mensajes a menudo era demasiado lento y algunas veces nos hacía perder información.

No he escrito juegos en varios años, y no sé cómo es .NET como plataforma de juegos. Es posible que la entrada siga siendo un problema, que la cola de mensajes simplemente no sea lo suficientemente rápida como para dar la respuesta rápida que los desarrolladores de juegos desean. Por lo tanto, omiten la cola de mensajes para tareas críticas.

+0

En realidad estaba pensando si sería necesario hacer un temporizador que conozca la frecuencia de la pantalla para crear marcos. De esa manera, siempre se realizan carreras innecesarias. También la idea acuñada por @Bryan Parker para tener el dibujo en un hilo separado para separarlo del resto (lógica del juego/IO) ... –

+0

... suena como una buena idea. No sé si es práctico. –

+1

La mayoría de los juegos tienen representación en un hilo separado ahora. Y desea poder desacoplar sus actualizaciones de vsync para pruebas de rendimiento (entre otras razones) – BigSandwich

1

Todos los programas que se ejecutan son bucles sin fin. Aunque en algunos casos no interactúa con el bucle (como en la programación web u otros programas menores)

Su sistema operativo es un bucle en espera de los comandos de entrada. Lo mismo con un juego. Un servidor web es un bucle en espera de solicitudes.

Una gran explicación es del usuario slim on one of my own questions.

+0

Básicamente tiene razón, aunque esto solo es cierto para los programas basados ​​en GUI. para aplicaciones triviales y de línea de comandos, puede escaparse fácilmente sin un bucle principal. –

+0

Agregó una aclaración. –

+0

Lee tu publicación y de hecho lo pensé. Pero dado que el sistema operativo ya está haciendo este ciclo, ¿no es una buena idea conectarse a ese bucle (usar los eventos del sistema operativo) en lugar de crear nuestro propio ciclo en el bucle del sistema operativo? –

0

colas de mensajes son bucles infinitos, así que hace que todos los programas como Bucles.

-3

si no se siente cómodo al respecto, paquete con la clase y la interfaz,

eso es lo que decimos "principio de apertura y cierre": abrir la interfaz nunca cambió, cerrar la parte sucia.

¿por qué usamos loop? porque es la estructura básica de nuestra computadora!

+0

Me temo que hay una falta de comunicación. Sé cómo podría ocultar todos los bits feos, pero la pregunta es por qué deberíamos implementar un bucle dentro del bucle del sistema operativo. –

1

El mejor bucle es un bucle sin fin con llamada de bloqueo para despachar eventos/mensajes. Si no hay nada que hacer, no debería dormir, sino bloquear mientras espera el SO. Pero si el sistema operativo no se bloquea cuando se sondean los eventos, dormir entre las encuestas es la única solución para evitar el uso de la CPU al 100%.

+0

Ok, eso es realmente lo que quise decir con sueño. (el viejo DoEvents). Cambiará la publicación para reflejar eso. –

1

No veo cómo se podría hacer de manera muy diferente?

La ejecución de su programa ocurre dentro de un hilo (o varios hilos, si le apetece). Tener un GameLoop (o una bomba Win32 GetMessage/DispatchMessage) tiene que ver con esperar a que ocurra un evento y luego manejarlo. La alternativa sería registrar devoluciones de llamadas, y luego llamar a HandleAllMyMessages(), que internamente haría más o menos lo mismo ... y eso realmente no le compraría nada.

El sistema operativo no podrá dividir mágicamente su programa en varios subprocesos, ya que no tiene conocimiento de lo que quiere hacer dentro de esos subprocesos. Engendrar un nuevo hilo para cada mensaje entrante sería tanto infierno de sincronización como de rendimiento.

1

En Win32 utilizar un temporizador MultiMedia llamar a mi garrapata gamelogic ...

// request 1ms period for timer 
g_mmTimer = timeBeginPeriod(1); 
if (g_mmTimer != TIMERR_NOERROR) 
    return false; 

//start game loop event timer/thread 
g_mmTimer = timeSetEvent(10, 10, DoUpdate, 0, TIME_PERIODIC); 

Opcionalmente, se puede hacer todo el dibujo en otro hilo de manera que la lógica del juego es automáticamente independiente de la velocidad de fotogramas.

2

Los juegos (en la mayoría de los casos) son simulaciones. Tradicionalmente, esto significa que actualizas la simulación, presentas su estado actual (por ejemplo, render graphics) y repites. La representación natural de esto es un bucle.

La bomba de mensajes Win32 por otro lado es una peculiaridad específica de la plataforma, orientada a las aplicaciones impulsadas por eventos que conforman la mayoría de las aplicaciones en Windows. De ninguna manera es el estándar para aplicaciones en todas las plataformas, por lo que no es sorprendente que no todo el software se adapte bien al modelo. Por lo tanto, para modificar un programa típico para que se ajuste al modelo de Win32, normalmente drene esa cola de una sola vez, una vez por iteración del ciclo, usando PeekMessage hasta que esté vacía. O bien, coloca esa lógica en un hilo separado y usa GetMessage según corresponda.

Para la mayoría de los juegos con rendimiento en mente, no hay otra forma práctica de hacerlo. En primer lugar, si intentas hacer que el juego sea impulsado por eventos en lugar de encuestados, necesitarás un tiempo de resolución más alta del que Windows puede darte de manera confiable si deseas mantener el alto rendimiento que ofrecen muchos juegos. En segundo lugar, Windows es solo una de las plataformas para las que están escritos los juegos, y la modificación del juego para que encaje perfectamente en el modelo de Win32 solo será un inconveniente para las plataformas de juego dedicadas que esperan el canon del juego en su lugar.

Finalmente, las preocupaciones sobre 'tomar 100% de CPU' están fuera de lugar. La mayoría de los juegos modernos están diseñados para ser utilizados en modo de pantalla completa con acceso exclusivo a hardware, no para ser una de varias otras aplicaciones que coexisten. Los clientes de estos juegos en realidad exigen que el juego haga el mayor uso posible de su hardware y esto no se puede hacer si hay llamadas deliberadas Sleep() o si las actualizaciones dependen de temporizadores externos que despiertan la aplicación N veces por segundo. Obviamente hay excepciones para muchos juegos, ej. aquellos que están diseñados para ejecutarse principalmente en una ventana, pero es importante notar la distinción.

+0

Fantástica respuesta y descripción general. –

+0

Tomar CPU 100% es ciertamente una preocupación válida y algo que debe evitarse. Incluso cuando está en primer plano en pantalla completa, no quiere perder ciclos de CPU. Interfiere con la administración de energía cada vez más con cada año que pasa. Cuando escribiste tu respuesta, solo habría sido una preocupación para las computadoras portátiles (que todavía es motivo suficiente para no quemar la CPU). Hoy, activará un núcleo de CPU en Turbo Boost, disminuyendo la potencia disponible para la GPU integrada. Entonces, tu idea de acaparar todos los recursos para tu juego en realidad disminuye su rendimiento. -1 –

+0

@BenVoigt: ese es un punto válido, pero depende de la plataforma a la que se dirija. Los juegos AAA que no están destinados exclusivamente a plataformas móviles o portátiles no introducirán deliberadamente ciclos de suspensión por ningún motivo y ampliarán el procesamiento para completar los recursos de CPU disponibles. Más específicamente, no se espera que produzcan un buen rendimiento en las GPU integradas: son ciudadanos de segunda clase en lo que respecta al software de juegos. Pero si apunta al móvil ... esa es una historia diferente. – Kylotan

0

MsgWaitForMultipleEvents combina funcionalidad GetMessage/PeekMessage con un tiempo de espera y la capacidad de esperar a que los objetos del núcleo, como un WaitableTimer.

He usado CreateWaitableTimer para configurar mi tasa de cuadros deseada junto con MsgWaitForMultipleEvents para el envío de mensajes con gran éxito para una animación muy suave en el pasado, sin agitación. Ojalá otros sistemas operativos tuvieran algo tan bueno.

Cuestiones relacionadas