Ejecutar Cocos2D desde un Tab Bar UIKit

Creo que este es el quebradero de cabeza para todos los que comienzan o han comenzado a usar Cocos2D. Usualmente queremos meter en un tabbar de una app tradicional Uikit una aplicación desarrollada en Cocos2D (u otras) y lo único que podemos hacer es levantar un puño al cielo y maldecir en voz alta, eso, o gritar ¡NO SÉ QUE HACER!.

Lo sé, been there done that. Sin embargo, a medida que vas “toqueteando” la herramienta, te das cuenta de lo esencial: El Director ha de instanciarse en el AppDelegate, porque es la BASE de Cocos2D, es quién dirige y dice cuando debe ejecutarse cualquier escena de la app.

IMPORTANTE: 
En Cocos2D puedes usar cualquier UiView + TabBars + Botones etc, PERO debes hacerlo partiendo de Cocos2D como base porque la plantilla instancia todas las llamadas, clases y el Director ya se instancia dentro del AppDelegate.
Hasta ahora no he logrado hacerlo al revés, es decir, partiendo desde una aplicación UIKIT bruta y añadirle el framework de Cocos2D. Hay que hacer muchas maromas para lograrlo, añadir librerías, licencias, clases, y un largo etcétera.
Si este eres tú: “Dame el código y ya veré por mi cuenta como funciona”
Descarga el código aquí –> Sí, aquí

 

Pero, si quieres leer todo el tutorial, sigue por aquí:

AppDelegate.h

¡Ok! Para comenzar no hay un .m sin un .h así que las variables y métodos accesores que vamos a emplear son los siguientes:
#import "uikit.h"
#import "General.h"
 
@class RootViewController;
@interface AppDelegate : NSObject{

   UIWindow *window;
   RootViewController *viewController;
   General *general;
   NSNotificationCenter *notifyCenter;
}
@property (nonatomic, retain) NSNotificationCenter *notifyCenter;
@property (nonatomic, retain) General *general;
@property (nonatomic, retain) UIWindow *window;

- (void) showUIViewController:(UIViewController *) controller;
- (void) hideUIViewController:(UIViewController *) controller;

@end

General es la clase UIViewController, donde hemos creado el Tab Bar Controller.

  • NSNotificacionCenter es utilizada para, como su nombre lo indica, realizar notificaciones desde cualquier lugar de la app e indicarle al Director en el AppDelegate que debe ejecutar tal o cual escena de Cocos2D.
  •  RootViewController es el controlador root que Cocos2D utiliza para  manejar las rotaciones del iPhone/iPod/iPad.
  • window una UIWindow que funcionará para comunicarse con el Director y darle la información de la ventana del dispositivo.

AppDelegate.m

1.- Vale, lo primero es modificar el AppDelegate.m, colocando dentro de applicationDidFinishLaunching una notificación (la clase notifyCenter que se encargará de enviarle mensajes al AppDelegate desde otras clases cuando debe ejecutar las escenas en Cocos2D).
 self.notifyCenter = [NSNotificationCenter defaultCenter];
 [notifyCenter addObserver:self selector:@selector(trackNotifications:) name:nil object:nil];

1. 2.- Se instancia una variable UIWindow
window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
 [window setUserInteractionEnabled:YES];
 [window setMultipleTouchEnabled:YES];

CCDirector *director = [CCDirector sharedDirector];
 // Create an EAGLView with a RGB8 color buffer, and a depth buffer of 24-bits
 EAGLView *glView = [EAGLView viewWithFrame:[window frame] kEAGLColorFormatRGBA8 depthFormat:0];
 [glView setMultipleTouchEnabled:YES];

// attach the openglView to the director
 [director setOpenGLView:glView];

// 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");

// make the OpenGLView a child of the main window
 [window addSubview:glView];

// make main window visible
 [window makeKeyAndVisible];

 2.-  Creamos una clase CCScene , en el código se llama GameScene, que no contendrá nada de código excepto por el que viene por defecto con la misma clase, solo servirá para que el Director sepa que es lo que deberá ejecutar, es como un cascarón o wrapper en Cocos2D. Luego instanciamos en el applicationDidFinishLaunching.

Ojo, escribo los comentarios dentro del código en inglés por comodidad y costumbre.

//This must be a CCScene Class, the Director will start to use Cocos2D
 GameScene *gs = [GameScene node];
 [[CCDirector sharedDirector] runWithScene:gs];

3.- Al final del applicationDidFinishLaunching  hacemos llamada a un XIB que contiene el Tab Bar Controller

//uiview to be opened
 General *principal;
 principal = [[General alloc] initWithNibName:@"General" bundle:nil];
 self.general = principal;
 [principal release];

4.-  Y por último hacemos la llamada al UIview

[self showUIViewController:general];

Método de Notificación: trackNotifications

Como comenté anteriormente, se hace un método de notificación de llamadas a escenas de Cocos2D de la siguiente forma (en el mismo AppDelegate)
- (void) trackNotifications: (NSNotification *) notification{
  id nname = [notification name];
  if([nname isEqual:@"empezarPrueba"]){
     [self hideUIViewController:general];
     
     // Obtain the shared director in order to...
     CCDirector *director = [CCDirector sharedDirector];
    
    // Sets landscape mode
     [director setDeviceOrientation:kCCDeviceOrientationLandscapeLeft];

   //CCDeviceOrientationPortrait
   // Turn on display FPS
     [director setDisplayFPS:NO];

   // Turn on multiple touches
     EAGLView *view = [director openGLView];
     [view setMultipleTouchEnabled:YES];

  // 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];
    [[CCDirector sharedDirector] pushScene: [CCTransitionMoveInB transitionWithDuration:0.0f scene
    [HelloWorldLayer scene]]];
  }
}
 Nótese que el Director está siendo instanciado en este método, y que por defecto  se suele hacer en el  applicationDidFinishLaunching, además pueden apreciar que hay una condicional si es igual al nombre de una notificación, en este caso “empezarPrueba”  y el Director hace un pushScene de la escena HelloWorldLayer que es la escena Cocos2D que quiero se ejecute. Si quiero varias escenas, basta con hacer varios condicionales IF con los nombres de las notificaciones para cada una.
 Los métodos showUIViewController y  hideUIViewController tienen por finalidad ejecutar animaciones relacionadas a las llamadas de escenas.

Clase General

General es una clase UIViewController, que se crea como cualquier otra clase, simplemente vas a File –> New –> New File y seleccionamos la clase UiKit que queramos usar. En el XIB colocamos el Tab Bar Controller.
El contenido de General.h es el siguiente
#import "uikit.h"

@interface General : UIViewController {
  IBOutlet UITabBarController *rootController;
}

@property (nonatomic, retain) IBOutlet UITabBarController *rootController;
@end

Es el código que se crea por defecto, de hecho no hay que hacer nada más en el .h ni nada más en el .m.

Clase  PreJuego

En PreJuego.m tenemos un método IBAction, es el que asociaremos al XIB (PreJuego.xib) para que se envíe la notificación al AppDelegate y el Director pueda ejecutar la escena en Cocos2D.
¿Por qué crear otra clase para hacer la llamada a la escena en Cocos2D?
Esto es así de enrevesado, porque los tabbar funcionan solo con los ViewControllers,  y no se puede asociar directamente del TabBar una escena cocos2D, por lo que hay que crear un UIViewController, y dentro de esta clase crear un botón (desde Utilities) , que hace el proceso de notificación de la escena Cocos2D en el AppDelegate.
Este es el código dentro de PreJuego.h
#import "uikit.h"
@interface PreJuego : UIViewController {
}
- (IBAction) empezarprueba: (id)sender;
@end

 

Este es el código dentro de PreJuego.m
- (IBAction) empezarprueba:(id)sender{
 [[NSNotificationCenter defaultCenter] postNotificationName:@"empezarPrueba" object:@""];
 }

 

DESCARGAR EL CÓDIGO AQUÍ
Pues eso, ya puedes ejecutar escenas cocos2D desde un Tab Bar. Espero que les ayude y se haya entendido. Si existe alguna duda, pueden escribirme un comentarios abajo.
Keep it up people!
P.D = perdonen que el código no esté identado, aún no logro que este snippet de WordPress funcionen bien. Grrr!
 

Sofia Swidarowicz

I'm an iOS Software Engineer mostly. Known as phynet in the internez. I'm me, full of memory failure and lovely karma.

 

Leave a Reply

Your email address will not be published. Required fields are marked *