2012-06-14 9 views
7

Ho un gioco alimentato con cocos2d che utilizza i menu UIKit, quindi uso solo il framework per un viewcontroller, che è il gioco stesso. Inoltre, ha solo una scena. Dal momento che cocos2d 2.0 il regista in sé è una sottoclasse UIViewController, quindi ho solo spingere nel mio MenuViewController quando l'utente tocca un pulsante di avvio:cocos2d 2.0-rc2: termina il director e riavvia

-(void)startGameButtonPressed { 

    CCDirectorIOS* director = (CCDirectorIOS *) [CCDirector sharedDirector]; 


    // Create an CCGLView with a RGB565 color buffer, and a depth buffer of 0-bits 
    self.glView = [CCGLView viewWithFrame:CGRectMake(0, 0, 480, 320) 
           pixelFormat:kEAGLColorFormatRGB565 //kEAGLColorFormatRGBA8 
           depthFormat:0 //GL_DEPTH_COMPONENT24_OES 
         preserveBackbuffer:NO 
           sharegroup:nil 
          multiSampling:NO 
          numberOfSamples:0]; 

    // attach the openglView to the director 
    [director setView:glView]; 
    [director runWithScene:[GameLayer scene]]; 
    [director setDelegate:(id <CCDirectorDelegate>) [[UIApplication sharedApplication] delegate]]; 
    [self.navigationController pushViewController:director animated:YES]; 
} 

Questo funziona bene per la prima volta il metodo viene chiamato, quando l'utente avvia il primo gioco. Quando il gioco è finito, chiamo [[CCDirector sharedDirector] end].

La maggior parte della configurazione del director viene eseguita nell'appDelegate (viene preso immutato dal modello Cocos2d predefinito). Ho inserito lo CCGLView come proprietà trattenuta nel mio MenuViewController, perché altrimenti l'app si arresta in modo anomalo quando viene chiamato [[CCDirector sharedDirector] end] e lo CCGLView non viene mantenuto. Penso che potrebbe essere un bug cocos2d. In [[CCDirector sharedDirector] end] il framework chiama [self setView:nil], ma tenta comunque di accedere alla vista in un secondo momento (probabilmente su un altro thread).

Il problema ora è che alla seconda chiamata del metodo precedente (quando l'utente desidera avviare un'altra partita dal menu), startGameButtonPressed, il regista viene premuto ma lo schermo rimane nero. Il gioco è in esecuzione e risponde, io proprio non vedo nulla. Qualcuno può aiutarmi, per favore?

+0

Io ho usato realmente una risposta a questa domanda pure. È il punto cruciale della mia applicazione in questo momento. – Echilon

risposta

8

OK, ho avuto lo stesso problema e sono stato in grado di "risolverlo".

Quando si imposta CCGLView e [director setView:], anche se si apre il controller, la scena esiste ancora. l'unica cosa che succede è che la scena si ferma.

Quindi, per fare in modo che il "riavvio" funzioni, è necessario controllare se c'è già una scena in esecuzione (anche se è ferma, e invece di runWithScene: si usa replaceScene:.

Ecco il mio codice in modo da vedere:

- (void)setupCocos2D { 
    CCGLView *glView = [CCGLView viewWithFrame:CGRectMake(0, 0, 320, 480) 
           pixelFormat:kEAGLColorFormatRGB565 //kEAGLColorFormatRGBA8 
           depthFormat:0 //GL_DEPTH_COMPONENT24_OES 
         preserveBackbuffer:NO 
           sharegroup:nil 
          multiSampling:NO 
          numberOfSamples:0]; 

// HERE YOU CHECK TO SEE IF THERE IS A SCENE RUNNING IN THE DIRECTOR ALREADY  
if(![director_ runningScene]){ 
    [director_ setView:glView]; // SET THE DIRECTOR VIEW 
    if(! [director_ enableRetinaDisplay:YES]) // ENABLE RETINA 
     CCLOG(@"Retina Display Not supported"); 

    [director_ runWithScene:[HelloWorldLayer scene]]; // RUN THE SCENE 

} else { 
    // THERE IS A SCENE, START SINCE IT WAS STOPPED AND REPLACE TO RESTART 
    [director_ startAnimation]; 
    [director_ replaceScene:[HelloWorldLayer scene]]; 
}  


[director_ setDelegate:(id <CCDirectorDelegate>) [[UIApplication sharedApplication] delegate]]; 

// I DO NOT PUSH BECAUSE I ALREADY PUSHED TO THIS CONTROLLER, SO I ADD THE COCOS2D VIEW AS A SUBVIEW 
[self.view addSubview:[director_ view]]; 

} 

Spero che questo codice vi aiuterà, perché ho trascorso un'intera giornata cercando di capire questo fuori. potrebbe non essere il modo corretto o anche il modo più bello, ma si sta lavorando :)

EDIT: Inoltre, non che se si pop la scena Cocos2d, non si hanno a [[CCDirector sharedDirector] end] come l'animazione sarà fermato quando la vista è dealloc/rimosso.

+0

Penso che il motivo per cui questo funziona è che non si spinge il regista come un viewcontroller, ma piuttosto si collega la GLView a una propria vista. Questo potrebbe essere un approccio migliore del mio però. – avf

+0

Un grande ringraziamento per questo post @gmogames. Ho passato ore a lottare con questo. – Echilon

+0

Well Said..Grazie per la tua risposta Valuable ... –

0

In base alla mia esperienza, Cocos non supporta realmente la terminazione e il riavvio, si comporta come se fosse terminata e praticamente si spegne.

Ci sono due cose che puoi provare, la prima (e mi è venuta in mente) è chiamare CC_DIRECTOR_INIT (potrebbe non essere il nome esatto) dopo che il regista è terminato, e prima che tu voglia avviarlo di nuovo.

Il secondo è quello di modificare il codice sorgente del regista e modificare il metodo end in modo che lasci i cocos in uno stato utilizzabile (interrompilo dal rilascio della vista e dall'eliminazione della cache, ecc.). In alternativa a questo, è possibile modificare il metodo start in modo che si assicuri che Cocos sia in uno stato utilizzabile prima dell'avvio.

Purtroppo, Cocos non semplifica l'utilizzo di UIKit + Cocos, ma con un po 'di fortuna.

2

Ciò che funziona è chiamare semplicemente startAnimation e stopAnimation nel director, ma mantenere la vista di cocos2d e riutilizzarla.

Qualsiasi tentativo di chiudere cocos2d e la sua vista OpenGL e reinizializzarlo in seguito causerà più o meno problemi, perché in realtà non è stato testato abbastanza bene. A parte il fatto che cocos2d funziona perfettamente con UIKit, ha solo gli stessi problemi di qualsiasi altra app OpenGL ES quando lo si mescola con le viste UIKit.

+0

Il problema con questo approccio è che l'intero gioco è ancora in memoria. Inoltre, ho provato a scattare la scena corrente (l'ultima in pila), ma ha gli stessi problemi. Penso che questo è un campo in cui cocos2d deve migliorare in modo significativo, in quanto questo non sembra essere un problema di OpenGL, ma più un problema del regista non essere in grado di impostare correttamente il GLview dopo la fine di una volta. – avf

5

ho trascorso diversi giorni alla ricerca di informazioni relative a questo, e condividere con voi la mia esperienza. Sto anche cercando di creare un gioco che carica in un UITableViewController, da cui il CCDirector viene caricata quando si tocca una cella. Questo è un gioco a turni Game Center, da qui il design (pensa Words With Friends). L'approccio migliore che ho trovato finora è il seguente (nota che sto lavorando in 2.0 - dove CCDirector è una sottoclasse UIViewController):

In AppDelegate.h, creare un nuovo ivar per contenere il CCGLView creato dal codice del modello. Quindi assegna il CCGLView creato in didFinishLaunching al tuo nuovo ivar. Questo permette al regista di riutilizzare la vista originariamente creato invece di cercare di ricreare ogni volta che si ricarica il CCDirector, che sembra causare tutta una serie di problemi strane nella mia esperienza.

anche voi volete creare un nuovo metodo in AppDelegate chiamato -setupDirector o qualcosa di simile, dove si vuole, bene, l'installazione il regista. Questo dovrebbe essere chiamato ogni volta che si ricrea il CCDirector. Ho pubblicato la mia versione qui sotto. Nota il mio ivar per CCGLView si chiama "GLView".

- (void)setupDirector { 
if (![CCDirector sharedDirector]) { 
    CCLOG(@"Calling setupDirector"); 

    director_ = (CCDirectorIOS*) [CCDirector sharedDirector]; 

    director_.wantsFullScreenLayout = YES; 

    // Display FSP and SPF 
    [director_ setDisplayStats:NO]; 

    // set FPS at 60 
    [director_ setAnimationInterval:1.0/60]; 

    // attach the openglView to the director 
    [director_ setView:GLView]; 

    // for rotation and other messages 
    [director_ setDelegate:self]; 

    // 2D projection 
    [director_ setProjection:kCCDirectorProjection2D]; 
    // [director setProjection:kCCDirectorProjection3D]; 

    // Enables High Res mode (Retina Display) on iPhone 4 and maintains low res on all other devices 
    if(! [director_ enableRetinaDisplay:YES]) 
     CCLOG(@"Retina Display Not supported"); 

    // Default texture format for PNG/BMP/TIFF/JPEG/GIF images 
    // It can be RGBA8888, RGBA4444, RGB5_A1, RGB565 
    // You can change anytime. 
    [CCTexture2D setDefaultAlphaPixelFormat:kCCTexture2DPixelFormat_RGBA8888]; 

    // If the 1st suffix is not found and if fallback is enabled then fallback suffixes are going to searched. If none is found, it will try with the name without suffix. 
    // On iPad HD : "-ipadhd", "-ipad", "-hd" 
    // On iPad  : "-ipad", "-hd" 
    // On iPhone HD: "-hd" 
    CCFileUtils *sharedFileUtils = [CCFileUtils sharedFileUtils]; 
    [sharedFileUtils setEnableFallbackSuffixes:NO];    // Default: NO. No fallback suffixes are going to be used 
    [sharedFileUtils setiPhoneRetinaDisplaySuffix:@"-hd"];  // Default on iPhone RetinaDisplay is "-hd" 
    [sharedFileUtils setiPadSuffix:@"-ipad"];     // Default on iPad is "ipad" 
    [sharedFileUtils setiPadRetinaDisplaySuffix:@"-ipadhd"]; // Default on iPad RetinaDisplay is "-ipadhd" 

    // Assume that PVR images have premultiplied alpha 
    [CCTexture2D PVRImagesHavePremultipliedAlpha:YES]; 
} 

Inoltre, si desidera apportare un paio di modifiche al modo in cui il modello carica i controller di visualizzazione. Normalmente, cocos2D imposta il controller di navigazione con director_ come controller della vista radice. Qui, si vuole alloc e init il controller di visualizzazione dei menu e aggiungere che, invece di director_:

// Create a Navigation Controller with the Director 
gamesTVC_ = [[GamesTableViewController alloc] initWithStyle:UITableViewStyleGrouped]; 
navController_ = [[UINavigationController alloc] initWithRootViewController:gamesTVC_]; 
navController_.navigationBarHidden = NO; 

Tutto il resto nella didFinishLaunching può rimanere lo stesso. Ora, nella vostra menuViewController nel metodo startGameButtonPressed, si chiama il metodo setupDirector appena creato sull'istanza app, che fa riferimento al numero:

AppController *app = (AppController *)[[UIApplication sharedApplication] delegate]; 
if ([CCDirector sharedDirector].runningScene) { 
    [[CCDirectorIOS sharedDirector] end]; 
} 
[app setupDirector]; 
[app.navController pushViewController:app.director animated:YES]; 

ho includono un controllo per assicurarsi che il CCDirector non è ancora in esecuzione e se lo è, terminalo. Nel vostro livello di gioco, quando arriva il momento che si desidera pop il controller della vista, vi sarà semplicemente chiamarlo in questo modo:

AppController *app = (AppController *)[[UIApplication sharedApplication] delegate]; 
[app.navController popViewControllerAnimated:YES]; 
[[CCDirector sharedDirector] end]; 

Questo flusso dovrebbe consentire di utilizzare liberamente un controller di navigazione per spingere la scena di gioco con CCDirector e apre il controller di visualizzazione quando vuoi tornare al menu principale basato su UIKit. Spero che questo aiuti, dato che ho trascorso un sacco di tempo frustrante cercando di farlo bene per il mio gioco.