2010-03-11 13 views
6

Soy nuevo en el desarrollo de iPhone, pero estoy tratando de construir un juego en 2D. Estaba siguiendo un libro, pero el bucle del juego se creó básicamente dije:¿Es esta una buena manera de hacer un ciclo de juego para un juego de iPhone?

function gameLoop 
    update() 
    render() 
    sleep(1/30th second) 
    gameLoop 

El razonamiento era que esto iría a 30 fps. Sin embargo, esto parecía un poco mental, porque si mi fotograma tuviese 1/30 de segundo, funcionaría a 15 fps (ya que pasaría tanto tiempo durmiendo como actualizando).

Así que investigué un poco y encontré la clase CADisplayLink que sincronizaría las llamadas a mi función gameLoop con la frecuencia de actualización (o una fracción de ella). No puedo encontrar muchas muestras de él, así que estoy publicando aquí para una revisión del código :-) Parece que funciona como se esperaba, e incluye pasar el tiempo transcurrido (fotograma) al método de actualización para que mi lógica pueda ser una tasa de fotogramas -independiente (sin embargo, en realidad no puedo encontrar en el documento lo que CADisplayLink haría si mi cuadro tomara más tiempo de lo que tenía permitido ejecutar, ¡espero que haga todo lo posible para ponerse al día y no se cuelgue!).

// 
// GameAppDelegate.m 
// 
// Created by Danny Tuppeny on 10/03/2010. 
// Copyright Danny Tuppeny 2010. All rights reserved. 
// 

#import "GameAppDelegate.h" 
#import "GameViewController.h" 
#import "GameStates/gsSplash.h" 

@implementation GameAppDelegate 

@synthesize window; 
@synthesize viewController; 

- (void) applicationDidFinishLaunching:(UIApplication *)application 
{ 
// Create an instance of the first GameState (Splash Screen) 
[self doStateChange:[gsSplash class]]; 

// Set up the game loop 
displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(gameLoop)]; 
[displayLink setFrameInterval:2]; 
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 
} 

- (void) gameLoop 
{ 
// Calculate how long has passed since the previous frame 
CFTimeInterval currentFrameTime = [displayLink timestamp]; 
CFTimeInterval elapsed = 0; 

// For the first frame, we want to pass 0 (since we haven't elapsed any time), so only 
// calculate this in the case where we're not the first frame 
if (lastFrameTime != 0) 
{ 
    elapsed = currentFrameTime - lastFrameTime; 
} 

// Keep track of this frames time (so we can calculate this next time) 
lastFrameTime = currentFrameTime; 

NSLog([NSString stringWithFormat:@"%f", elapsed]); 

// Call update, passing the elapsed time in 
[((GameState*)viewController.view) Update:elapsed]; 
} 

- (void) doStateChange:(Class)state 
{ 
// Remove the previous GameState 
if (viewController.view != nil) 
{ 
    [viewController.view removeFromSuperview]; 
    [viewController.view release]; 
} 

// Create the new GameState 
viewController.view = [[state alloc] initWithFrame:CGRectMake(0, 0, IPHONE_WIDTH, IPHONE_HEIGHT) andManager:self]; 

// Now set as visible 
[window addSubview:viewController.view]; 
[window makeKeyAndVisible]; 
} 

- (void) dealloc 
{ 
[viewController release]; 
    [window release]; 
    [super dealloc]; 
} 

@end 

Cualquier comentario sería apreciada :-)

PS. Puntos de bonificación si me puede decir por qué todos los libros usan "viewController.view", pero para todo lo demás parece usar el formato "[object name]". ¿Por qué no [viewController view]?

+0

Aunque este código funciona, parece tartamudear un poco. La velocidad de fotogramas no es baja, simplemente no parece suave. Creo que esto puede deberse a que estoy sincronizando con la velocidad de fotogramas y luego * actualizando * en mi bucle de juego. La renderización se realiza en drawRect. Creo que mi código debe dibujarse directamente en el método llamado (y tal vez la actualización se debe hacer después del sorteo), pero no puedo encontrar ningún buen ejemplo de CADisplayLink. –

+0

Cambié el movimiento de mis sprites a 30 píxeles por segundo, y parece completamente suave (con el marco muy ocasional caído), así que creo que fue solo por la velocidad que había establecido, por ejemplo. moviéndose un poco más de un píxel por cuadro, lo que significaba que eventualmente saltaría dos píxeles en un cuadro, lo que lo haría parecer desigual. Supongo que esto es inevitable. –

Respuesta

2

Tiene Cocos2D enumerado como una etiqueta en su pregunta, pero en realidad no está usando ningún código Cocos2D. ¿Has considerado hacer una implementación de Cocos2D para tus juegos? Le ahorrará un poco de molestia innecesaria.

En cuanto a su pregunta de sintaxis [myObject view] se utiliza para llamar a métodos en myObject, mientras que myObject.view se utiliza para establecer/obtener variables de instancia expuestas como propiedades. No recuerdo si puede recuperar variables de instancia usando [myObject view] también, pero si eso funciona, entonces supongo que la única diferencia entre las dos es la sintaxis y puede usar ambos métodos para recuperar variables de instancia.

Espero que algo de eso divague sea útil para ti.

+0

¡Vaya! ¡Te dije que no sabía lo que estaba haciendo! Se eliminó la etiqueta ahora. Leí algo sobre la sintaxis, comprenda mejor ahora. Parece que [propiedad myclass] y myclass.property pueden hacer cosas diferentes. La primera es una propiedad (que puede ejecutar código, aunque en la mayoría de los casos sospecho que solo devuelve la variable) mientras que el punto accede a la variable directamente (y no tendrá un código personalizado). Parece ser la diferencia entre exponer un campo privado y una propiedad en C#, ¡solo que aquí ambos pueden parecer tener el mismo nombre! –

+0

En realidad, ahora estoy confundido, porque estoy recibiendo errores: accediendo al método desconocido 'rect' getter Lo que me hace pensar que usar dot es exactamente lo mismo que usar los métodos get/set! –

+0

Si usa el punto, necesita definir la variable de instancia que desea recuperar como una propiedad y luego sintetizarla también. Sintaxis de búsqueda para las llamadas "@property" y "@synthesize". Los métodos Getter/setter se crean implícitamente para usted, pero solo después de utilizar @synthesize. Es por eso que está obteniendo un método de obtención de 'rect' desconocido. –

-2

De muchos ejemplos GL de Apple, creo que deberías usar un temporizador.

animationTimer = [NSTimer scheduledTimerWithTimeInterval:(1.0/60.0) 
                target:self 
               selector:@selector(updateAndRender) 
               userInfo:nil 
               repeats:TRUE]; 
+0

Creo que se agregó CADisplayLink como una mejor manera, pero debido a que fue agregado recientemente, parece haber poca documentación/muestras :( –

Cuestiones relacionadas