2011-10-27 15 views
6

Quiero separar la lógica del juego y la renderización en dos bucles diferentes, porque no quiero que los fps controlen la velocidad del juego. Traté de lograr esto creando un CADisplayLink para el renderizado y un NSTimer para la lógica del juego. Pero luego sucedió algo extraño:Bucle de juego con temporizador separado para renderizar y lógica de juego

A veces (1 de cada 15 ejecuciones de aplicaciones) el juego se ejecuta en un fps muy bajo (alrededor de 5-10), pero el resto del tiempo es completamente uniforme. Si elimino el NSTimer de la lógica del juego y combino los dos bucles, el fps es constantemente alto, pero obviamente no es una solución aceptable. Parece que a veces los dos temporizadores se "retrasan" o algo así, pero no entiendo completamente el funcionamiento interno de los runloops.

Así es como se crea el temporizador y el displaylink:

NSTimer *gameTimer = [[NSTimer alloc] initWithFireDate:[NSDate date] interval:1.0/60.0 target:self selector:@selector(gameTimerFired:) userInfo:nil repeats:YES]; 
[[NSRunLoop mainRunLoop] addTimer:gameTimer forMode:NSDefaultRunLoopMode]; 
[gameTimer release]; 

CADisplayLink *aDisplayLink = [[UIScreen mainScreen] displayLinkWithTarget:self selector:@selector(drawFrame)]; 
[aDisplayLink setFrameInterval:animationFrameInterval]; 
[aDisplayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 
self.displayLink = aDisplayLink; 

¿Me puede decir lo que causa el problema fps y cómo solucionarlo?

¿O puede recomendar alguna otra solución para separar la reproducción y el bucle lógico del juego?

+0

No se supone que crear dos bucles de separar la velocidad del juego y fps ... – thedaian

+0

Entonces, ¿cómo puedo hacerlo con un bucle? – mikabast

Respuesta

3

Puede hacer esto con un ciclo utilizando su gameTimer o CADisplayLink midiendo el tiempo transcurrido desde el último ciclo y usándolo para aumentar la lógica de su juego.

Así que ..

NSDate *oldTime = [[NSDate date] retain]; 

-(void)updateGame { 
    NSDate *curTime = [NSDate date]; 
    NSTimeInterval timePassed_ms = [curTime timeIntervalSinceDate:oldTime] * 1000.0; 

    [oldTime release]; 
    oldTime = curTime; 
    [oldTime retain]; 

    //use the timePassed_ms to augment your game logic. IE: Moving a ship 
    [ship moveLength:ship.velocity * timePassed_ms/1000.0]; 
} 

Eso es por lo general la forma en que manejo este tipo de cosas. Por lo general, me gusta crear funciones de actualización directamente en mis objetos del juego. Así que la actualización de la nave en realidad se vería así:

[ship update:timePassed_mc]; 
+0

Gracias por la sugerencia. Inspiró mi solución final (ver más abajo). – mikabast

0

Tenga en cuenta que NSTimer no le dará ningún tipo de sincronización confiable. Está cerca, pero no está garantizado, y si ejecutas un bucle de juego, obtendrás el marco caído ocasionalmente.

Puede hacer su lógica de juego en un subproceso, y dormir hasta el siguiente fotograma (esto no será una cantidad de tiempo constante).

+0

NSTimer no es realmente confiable, pero desde la perspectiva de la experiencia del usuario, 56 actualizaciones por segundo o 64 actualizaciones por segundo realmente no hacen la diferencia. Pero si actualizo los objetos del juego solo cuando dibujo, puede caer a 20 o 30 actualizaciones por segundo en dispositivos más lentos, cuando se ejecuta el doble de rápido en dispositivos más rápidos. – mikabast

1

así que terminé usando lo que sugiere Andrew Zimmern, con algunas pequeñas modificaciones, ya que se actualiza el juego de objetos entre sí entre intervalos iguales.

Así que estoy usando solo un bucle, el que lanzó CADisplayLink. Aquí está el código final:

- (void)drawFrame 
{ 
    if (!isGameTimerPaused) 
    { 
     NSDate *newDate = [NSDate date]; 
     timeSinceLastUpdate += [newDate timeIntervalSinceDate:lastUpdateDate]; 

     while (timeSinceLastUpdate > 1.0/60.0) 
     { 
      [self updateGame]; // UPDATE GAME OBJECTS 
      timeSinceLastUpdate -= 1.0/60.0; 
     } 

     [lastUpdateDate release]; 
     lastUpdateDate = [newDate retain]; 
    } 


    // DRAWING CODE HERE 
    (...) 
    // 
} 
+0

¡Me alegro de que esto funcione para ti! Tenga en cuenta que puede ver cierta degradación del rendimiento si está realizando un gran procesamiento en la función updateGame (como la detección de colisiones entre muchos objetos). ¡Salud! –

Cuestiones relacionadas