Juegos iOS y gestión de bucle de ejecución

Primero, mi pregunta: ¿Cómo administras tu iOS Run-Loop?

A continuación, mi razón: He estado investigando esto con una variedad de prototypes (v. Desarrollo de etapa temprana) y he encontrado una serie de problemas desconcertantes.

  • Primero, los problemas de input y el ciclo de ejecución me llevan a probar lo siguiente:
    • cuando uso el sistema más recomendado (CADisplayLink) noté que ciertas inputs táctiles se caen una vez que la carga de la CPU provoca que el buffer flip (presentRenderBuffer) tenga que esperar un cuadro. Esto ocurre solo en el dispositivo y no en el simulador (molesto: esto parece estar relacionado con esperar el locking de vsync en el hilo principal y la forma en que el process de ciclo de ejecución de la aplicación toca la input y recibe los posts)
    • cuando utilizo el siguiente sistema más recomendado (NSTimer) noté que ciertas inputs táctiles se caen una vez que la carga de la CPU alcanza un cierto punto en el simulador pero no en el dispositivo (también molesto). NSTimer también resulta en una precisión mucho menor cuando mis actualizaciones se disparan
    • cuando se usa el sistema less recomendado (ejecutando el bucle de ejecución en su propio hilo administrado internamente con un timer de alta precisión construido desde mach_absolute_time, todos mis problemas de input táctil desaparecen, sin embargo, mi código ASSERT ahora atrapa el hilo equivocado y solo si duermo después de la interrupción del software. (Mi código asertivo es similar a http://iphone.m20.nl/wp/?p=1 ) Realmente me gusta tener mi código Assert atrapado inmediatamente en la línea que causó el problema, por lo que esta solución es Realmente no funciona para mí: más difícil de depurar.
  • Segundo, time perdido:
    • mientras investigaba el sistema, descubrí que, independientemente del framerate (extrañamente, pero supongo que estadísticamente todavía tiene sentido w / vsync), estoy esperando aproximadamente el 22% del time en el vsync. Lo he confirmado moviendo glFlush / glFinish y jugando con la frecuencia con que hago las llamadas presentRenderBuffer. Este es el momento key que me gustaría procesar AI, etc. en lugar de limitarme a bloquear una llamada gl. La única forma en que puedo pensar alnetworkingedor de esto implicaría trasladar la representación a su propio hilo, pero no estoy seguro si se justifica comenzar a volver a diseñar para múltiples subprocesss en un dispositivo de procesador único.

Entonces, ¿alguien ha encontrado una bala mágica en torno a estos problemas? ¿Alguien tiene una architecture de run-loop asesina que es pateada en esta plataforma? Por el momento parece que tengo que elegir el menor de los males.

Para mis propios proyectos de iOS, uso el enfoque clásico (crear una window .nib, crear una class que henetworkinga EAGLView , agregar EAGLView a una vista en un controller de vista que se coloca en su propia .nib).

En el trabajo, tomé un enfoque ligeramente diferente inspirado en SDL, que puedes inspeccionar en nuestra biblioteca opensource, APRIL . El objective principal de APRIL es el soporte para tantas plataforms como sea posible, manteniendo la simplicidad (administración de windows y inputs solamente) y siendo claros sobre los problemas de licenciamiento y de uso gratuito. Nuestros desarrolladores quieren escribir aplicaciones en una plataforma (Windows, Mac o Linux, de acuerdo con los gustos y deseos) y luego me entregan el código para adaptarse a otras plataforms.

En el enfoque que usamos en APRIL, no crea ningún .nibs, y al llamar a UIApplicationMain , especifica la class de delegado como su cuarto argumento. El código principal del juego sigue siendo el mismo para cada plataforma, y ​​solo el contenido específico de la plataforma es #ifdef 'd en el código, o abstraído en una biblioteca auxiliar.

En el delegado de la aplicación, crea el controller de vista y la window:

 - (void)applicationDidFinishLaunching:(UIApplication *)application { // create a window. // early creation so Default.png can be displayed while we're waiting for // game initialization window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; // viewcontroller will automatically add imageview viewController = [[AprilViewController alloc] initWithWindow:window]; [viewController loadView]; // set window color [window setBackgroundColor:[UIColor blackColor]]; // display the window [window makeKeyAndVisible]; // thanks to Kyle Poole for this trick // also used in latest SDL // quote: // KP: using a selector gets around the "failed to launch application in time" if the startup code takes too long // This is easy to see if running with Valgrind [self performSelector:@selector(runMain:) withObject:nil afterDelay:0.2f]; } 

¿Observe cómo retrasamos el lanzamiento por 0.2? Es por eso que menciono la vista de image arriba. Durante esos 0.2 segundos, tendríamos una pantalla en blanco que se muestra inmediatamente después de Default.png, y se introduce un retraso adicional antes de que el control se transfiera a runMain :, que libera el control a la aplicación principal:

 - (void)runMain:(id)sender { // thanks to Kyle Poole for this trick char *argv[] = {"april_ios"}; int status = april_RealMain (1, argv); //gArgc, gArgv); #pragma unused(status) } 

Entonces, ahora el control nunca se transfiere al bucle principal real de UIApplication. A continuación, crea tu propio bucle principal.

  void iOSWindow::enterMainLoop() { while (mRunning) { // parse UIKit events doEvents(); handleDisplayAndUpdate(); } } void iOSWindow::doEvents() { SInt32 result; do { result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, TRUE); } while(result == kCFRunLoopRunHandledSource); } 

(En una nota lateral, el controller de vista se usa, por supuesto, para simplificar la rotation de la interfaz de usuario para que coincida con la orientación del dispositivo).

Ambos methods usan CADisplayLink si el sistema operativo lo admite. No he notado ningún problema con ninguno de los methods, aunque mis proyectos privados están basados ​​principalmente en el acelerómetro. Sospecho que el enfoque APRIL podría hacer que algunos de los problemas desaparezcan también.