{"id":379,"date":"2012-04-01T19:36:45","date_gmt":"2012-04-01T19:36:45","guid":{"rendered":"http:\/\/phyline.com\/blog\/?p=379"},"modified":"2015-08-13T18:57:43","modified_gmt":"2015-08-13T18:57:43","slug":"unir-cocos2d-en-una-app-uikit","status":"publish","type":"post","link":"http:\/\/sophyonline.com\/blog\/2012\/04\/unir-cocos2d-en-una-app-uikit\/","title":{"rendered":"Ejecutar Cocos2D desde un Tab Bar UIKit"},"content":{"rendered":"<p>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\u00f3n desarrollada en Cocos2D (u otras) y lo \u00fanico que podemos hacer es levantar un pu\u00f1o al cielo y maldecir en voz alta, eso, o gritar \u00a1NO S\u00c9 QUE HACER!.<\/p>\n<p>Lo s\u00e9, been there done that. Sin embargo, a medida que vas &#8220;toqueteando&#8221; la herramienta, te das cuenta de lo\u00a0esencial:\u00a0<span style=\"color: #ff6600;\"><em><strong>El Director ha de instanciarse en el AppDelegate<\/strong><\/em><\/span>, porque es la <span style=\"color: #ff6600;\"><strong>BASE<\/strong><\/span> de Cocos2D, es qui\u00e9n dirige y dice cuando debe ejecutarse cualquier escena de la app.<\/p>\n<div><strong>IMPORTANTE:\u00a0<\/strong><\/div>\n<div>En Cocos2D puedes usar cualquier UiView + TabBars + Botones etc, PERO debes\u00a0hacerlo partiendo de Cocos2D como base porque la plantilla instancia todas las llamadas, clases y el Director ya se instancia dentro del AppDelegate.<\/div>\n<div><\/div>\n<div>Hasta ahora no he logrado hacerlo al rev\u00e9s, es decir, partiendo desde una aplicaci\u00f3n UIKIT bruta y a\u00f1adirle el framework de Cocos2D. Hay que hacer muchas maromas para lograrlo, a\u00f1adir librer\u00edas, licencias, clases, y un largo etc\u00e9tera.<\/div>\n<div><\/div>\n<div><\/div>\n<div style=\"text-align: center;\"><span style=\"color: #000000;\">Si este eres t\u00fa: <strong>&#8220;Dame el c\u00f3digo y ya ver\u00e9 por mi cuenta como funciona&#8221;<\/strong><\/span><\/div>\n<div><img decoding=\"async\" class=\" aligncenter\" src=\"http:\/\/profile.ak.fbcdn.net\/hprofile-ak-snc4\/211174_160016684059453_6344475_n.jpg\" alt=\"\" \/><\/div>\n<div style=\"text-align: center;\">Descarga el c\u00f3digo aqu\u00ed &#8211;&gt;<span style=\"color: #ff6600;\"> <a href=\"http:\/\/sophyonline.com\/blog\/codigoCocos2D\/uikitcocos\/Pruebauikit.zip\"><span style=\"color: #ff6600;\">S\u00ed, aqu\u00ed<\/span><\/a><\/span><\/div>\n<div><\/div>\n<div><\/div>\n<p>&nbsp;<\/p>\n<div><span style=\"color: #000000;\"><strong>Pero, si\u00a0quieres leer todo el tutorial, sigue por aqu\u00ed:<\/strong><\/span><\/div>\n<div>\n<h2><\/h2>\n<h2><span style=\"color: #000000;\"><strong>AppDelegate.h<\/strong><\/span><\/h2>\n<\/div>\n<div><\/div>\n<div>\u00a1Ok! Para comenzar no hay un .m sin un .h as\u00ed que las variables y m\u00e9todos accesores que vamos a emplear son los siguientes:<\/div>\n<div><\/div>\n<pre>#import \"uikit.h\"\r\n#import \"General.h\"\r\n \r\n@class RootViewController;\r\n@interface AppDelegate : NSObject{\r\n\r\n   UIWindow *window;\r\n   RootViewController *viewController;\r\n   General *general;\r\n   NSNotificationCenter *notifyCenter;\r\n}\r\n@property (nonatomic, retain) NSNotificationCenter *notifyCenter;\r\n@property (nonatomic, retain) General *general;\r\n@property (nonatomic, retain) UIWindow *window;\r\n\r\n- (void) showUIViewController:(UIViewController *) controller;\r\n- (void) hideUIViewController:(UIViewController *) controller;\r\n\r\n@end<\/pre>\n<p><span style=\"color: #ff6600;\"><strong>General<\/strong><\/span> es la clase UIViewController, donde hemos creado el Tab Bar Controller.<\/p>\n<ul>\n<li><span style=\"color: #ff6600;\"><strong>NSNotificacionCenter<\/strong><\/span> 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.<\/li>\n<li>\u00a0<strong><span style=\"color: #ff6600;\">RootViewController <\/span><\/strong>es el controlador root que Cocos2D utiliza para \u00a0manejar las rotaciones del iPhone\/iPod\/iPad.<\/li>\n<li><strong style=\"color: #ff6600;\">window <\/strong><span style=\"color: #808080;\">una UIWindow que funcionar\u00e1 para comunicarse con el Director y darle la informaci\u00f3n de la ventana del dispositivo.<\/span><\/li>\n<\/ul>\n<div><\/div>\n<h2><span style=\"color: #000000;\"><em><strong>AppDelegate.m<\/strong><\/em><\/span><\/h2>\n<div><\/div>\n<div>1.- Vale, lo primero es modificar el AppDelegate.m, colocando dentro de <strong><em>applicationDidFinishLaunching<\/em><\/strong> una <strong><span style=\"color: #ff6600;\">notificaci\u00f3n<\/span><\/strong> (la clase notifyCenter que se encargar\u00e1 de enviarle mensajes al AppDelegate desde otras clases cuando debe ejecutar las escenas en Cocos2D).<\/div>\n<div><\/div>\n<div>\n<pre> self.notifyCenter = [NSNotificationCenter defaultCenter];\r\n [notifyCenter addObserver:self selector:@selector(trackNotifications:) name:nil object:nil];\r\n\r\n<\/pre>\n<\/div>\n<div>1. 2.- Se instancia una variable UIWindow<\/div>\n<div>\n<pre>window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];\r\n [window setUserInteractionEnabled:YES];\r\n [window setMultipleTouchEnabled:YES];\r\n\r\nCCDirector *director = [CCDirector sharedDirector];\r\n \/\/ Create an EAGLView with a RGB8 color buffer, and a depth buffer of 24-bits\r\n EAGLView *glView = [EAGLView viewWithFrame:[window frame] kEAGLColorFormatRGBA8 depthFormat:0];\r\n [glView setMultipleTouchEnabled:YES];\r\n\r\n\/\/ attach the openglView to the director\r\n [director setOpenGLView:glView];\r\n\r\n\/\/ Enables High Res mode (Retina Display) on iPhone 4 and maintains low res on all other devices\r\n if( ! [director enableRetinaDisplay:YES] )\r\n CCLOG(@\"Retina Display Not supported\");\r\n\r\n\/\/ make the OpenGLView a child of the main window\r\n [window addSubview:glView];\r\n\r\n\/\/ make main window visible\r\n [window makeKeyAndVisible];<\/pre>\n<\/div>\n<div>\n<p>\u00a02.- \u00a0Creamos una <strong><span style=\"color: #ff6600;\">clase CCScene<\/span><\/strong>\u00a0, en el c\u00f3digo se llama GameScene, que no contendr\u00e1 nada de c\u00f3digo excepto por el que viene por defecto con la misma clase, solo servir\u00e1 para que el Director sepa que es lo que deber\u00e1 ejecutar, es como un cascar\u00f3n o wrapper en Cocos2D. Luego instanciamos en el\u00a0<em><strong>applicationDidFinishLaunching.<\/strong><\/em><\/p>\n<p>Ojo, escribo los comentarios dentro del c\u00f3digo en ingl\u00e9s por comodidad y costumbre.<\/p>\n<\/div>\n<div>\n<pre>\/\/This must be a CCScene Class, the Director will start to use Cocos2D\r\n GameScene *gs = [GameScene node];\r\n [[CCDirector sharedDirector] runWithScene:gs];<\/pre>\n<p>3.- Al final del <em><strong>applicationDidFinishLaunching\u00a0<\/strong><\/em>\u00a0hacemos llamada a un XIB que contiene el <span style=\"color: #ff6600;\"><strong>Tab Bar Controller<\/strong><\/span><\/p>\n<\/div>\n<pre>\/\/uiview to be opened\r\n General *principal;\r\n principal = [[General alloc] initWithNibName:@\"General\" bundle:nil];\r\n self.general = principal;\r\n [principal release];<\/pre>\n<div>\n<p>4.- \u00a0Y por \u00faltimo hacemos la llamada al UIview<\/p>\n<\/div>\n<pre>[self showUIViewController:general];\r\n<\/pre>\n<h2><span style=\"color: #000000;\"><strong><em>M\u00e9todo de Notificaci\u00f3n:\u00a0trackNotifications<\/em><\/strong><\/span><\/h2>\n<div>Como coment\u00e9 anteriormente, se hace un m\u00e9todo de notificaci\u00f3n de llamadas a escenas de Cocos2D de la siguiente forma (en el mismo AppDelegate)<\/div>\n<div><\/div>\n<div>\n<pre>- (void) trackNotifications: (NSNotification *) notification{\r\n  id nname = [notification name];\r\n  if([nname isEqual:@\"empezarPrueba\"]){\r\n     [self hideUIViewController:general];\r\n     \r\n     \/\/ Obtain the shared director in order to...\r\n     CCDirector *director = [CCDirector sharedDirector];\r\n    \r\n    \/\/ Sets landscape mode\r\n     [director setDeviceOrientation:kCCDeviceOrientationLandscapeLeft];\r\n\r\n   \/\/CCDeviceOrientationPortrait\r\n   \/\/ Turn on display FPS\r\n     [director setDisplayFPS:NO];\r\n\r\n   \/\/ Turn on multiple touches\r\n     EAGLView *view = [director openGLView];\r\n     [view setMultipleTouchEnabled:YES];\r\n\r\n  \/\/ Default texture format for PNG\/BMP\/TIFF\/JPEG\/GIF images\r\n  \/\/ It can be RGBA8888, RGBA4444, RGB5_A1, RGB565\r\n  \/\/ You can change anytime.\r\n\r\n    [CCTexture2D setDefaultAlphaPixelFormat:kCCTexture2DPixelFormat_RGBA8888];\r\n    [[CCDirector sharedDirector] pushScene: [CCTransitionMoveInB transitionWithDuration:0.0f scene\r\n    [HelloWorldLayer scene]]];\r\n  }\r\n}<\/pre>\n<\/div>\n<div>\u00a0N\u00f3tese que el Director est\u00e1 siendo instanciado en este m\u00e9todo, y que por defecto \u00a0se suele hacer en el \u00a0<span style=\"color: #ff6600;\"><strong><em>applicationDidFinishLaunching<\/em><\/strong><\/span>, adem\u00e1s pueden apreciar que hay una condicional si es igual al nombre de una notificaci\u00f3n, en este caso &#8220;empezarPrueba&#8221; \u00a0y el Director hace un pushScene de la escena <span style=\"color: #ff6600;\"><strong>HelloWorldLayer <\/strong><\/span>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.<\/div>\n<div><\/div>\n<div>\u00a0Los m\u00e9todos\u00a0<span style=\"color: #ff6600;\"><em><strong>showUIViewController<\/strong><\/em><\/span> y \u00a0<strong><em><span style=\"color: #ff6600;\">hideUIViewController <\/span><\/em><\/strong>tienen por finalidad ejecutar animaciones relacionadas a las llamadas de escenas.<\/div>\n<div><\/div>\n<h2><span style=\"color: #000000;\"><strong>Clase General<\/strong><\/span><\/h2>\n<div><\/div>\n<div><\/div>\n<div><\/div>\n<div><a href=\"http:\/\/sophyonline.com\/blog\/wp-content\/uploads\/2012\/04\/Captura-de-pantalla-2012-04-01-a-las-20.10.50.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-439\" title=\"Tab Bar Controller\" src=\"http:\/\/sophyonline.com\/blog\/wp-content\/uploads\/2012\/04\/Captura-de-pantalla-2012-04-01-a-las-20.10.50.png\" alt=\"\" width=\"452\" height=\"310\" \/><\/a><\/div>\n<div><\/div>\n<div>General es una clase UIViewController, que se crea como cualquier otra clase, simplemente vas a File &#8211;&gt; New &#8211;&gt; New File y seleccionamos la clase UiKit que queramos usar. En el XIB colocamos el Tab Bar Controller.<\/div>\n<div><\/div>\n<div>El contenido de <span style=\"color: #ff6600;\"><em><strong>General.h<\/strong><\/em><\/span> es el siguiente<\/div>\n<div><\/div>\n<pre>#import \"uikit.h\"\r\n\r\n@interface General : UIViewController {\r\n  IBOutlet UITabBarController *rootController;\r\n}\r\n\r\n@property (nonatomic, retain) IBOutlet UITabBarController *rootController;\r\n@end<\/pre>\n<div>\n<p>Es el c\u00f3digo que se crea por defecto, de hecho no hay que hacer nada m\u00e1s en el .h ni nada m\u00e1s en el .m.<\/p>\n<\/div>\n<div><\/div>\n<h2><span style=\"color: #000000;\"><em><strong>Clase \u00a0PreJuego<\/strong><\/em><\/span><\/h2>\n<div><\/div>\n<div>\n<div><em>En<strong>\u00a0PreJuego.m\u00a0<\/strong><\/em>tenemos un m\u00e9todo IBAction, es el que asociaremos al XIB (PreJuego.xib) para que se env\u00ede la notificaci\u00f3n al AppDelegate y el Director pueda ejecutar la escena en Cocos2D.<\/div>\n<div><\/div>\n<div><em><strong>\u00bfPor qu\u00e9 crear otra clase para hacer la llamada a la escena en Cocos2D?<\/strong><\/em><\/div>\n<div>Esto es as\u00ed de enrevesado, porque\u00a0los tabbar funcionan solo con los <em><strong><span style=\"color: #ff6600;\">ViewControllers<\/span><\/strong><\/em>, \u00a0y 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\u00f3n (desde Utilities) , que hace el proceso de notificaci\u00f3n de la escena Cocos2D en el AppDelegate.<\/div>\n<div><\/div>\n<div>Este es el c\u00f3digo dentro de PreJuego.h<\/div>\n<div><\/div>\n<div>\n<pre>#import \"uikit.h\"\r\n@interface PreJuego : UIViewController {\r\n}\r\n- (IBAction) empezarprueba: (id)sender;\r\n@end<\/pre>\n<p>&nbsp;<\/p>\n<\/div>\n<div><\/div>\n<div>Este es el c\u00f3digo dentro de PreJuego.m<\/div>\n<div>\n<pre>- (IBAction) empezarprueba:(id)sender{\r\n [[NSNotificationCenter defaultCenter] postNotificationName:@\"empezarPrueba\" object:@\"\"];\r\n }<\/pre>\n<p>&nbsp;<\/p>\n<\/div>\n<div><span style=\"color: #ff6600;\"><a href=\"http:\/\/sophyonline.com\/blog\/codigoCocos2D\/uikitcocos\/Pruebauikit.zip\"><span style=\"color: #ff6600;\">DESCARGAR EL C\u00d3DIGO AQU\u00cd<\/span><\/a><\/span><\/div>\n<div><\/div>\n<div>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.<\/div>\n<\/div>\n<div><\/div>\n<div>Keep it up people!<\/div>\n<div><\/div>\n<div>P.D = perdonen que el c\u00f3digo no est\u00e9 identado, a\u00fan no logro que este snippet de WordPress funcionen bien. Grrr!<\/div>\n","protected":false},"excerpt":{"rendered":"<p>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\u00f3n desarrollada en Cocos2D (u otras) y lo \u00fanico que podemos hacer es levantar un pu\u00f1o al cielo y maldecir en voz alta, eso, <a class=\"read-more\" href=\"http:\/\/sophyonline.com\/blog\/2012\/04\/unir-cocos2d-en-una-app-uikit\/\">&hellip;&nbsp;<span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"nf_dc_page":"","footnotes":""},"categories":[],"tags":[],"class_list":["post-379","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"http:\/\/sophyonline.com\/blog\/wp-json\/wp\/v2\/posts\/379","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/sophyonline.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/sophyonline.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/sophyonline.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/sophyonline.com\/blog\/wp-json\/wp\/v2\/comments?post=379"}],"version-history":[{"count":142,"href":"http:\/\/sophyonline.com\/blog\/wp-json\/wp\/v2\/posts\/379\/revisions"}],"predecessor-version":[{"id":650,"href":"http:\/\/sophyonline.com\/blog\/wp-json\/wp\/v2\/posts\/379\/revisions\/650"}],"wp:attachment":[{"href":"http:\/\/sophyonline.com\/blog\/wp-json\/wp\/v2\/media?parent=379"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/sophyonline.com\/blog\/wp-json\/wp\/v2\/categories?post=379"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/sophyonline.com\/blog\/wp-json\/wp\/v2\/tags?post=379"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}