Portal: Still Alive

This was a triumph. I'm making a note here: HUGE SUCCESS, It's hard to overstate my satisfaction. Aperture Science: We do what we must because we can for the good of all of us except for the ones who are dead, but there's no sense crying over every mistake. You just keep on trying 'till you run out of cake and the science gets done and you make a neat gun for the people who are still alive.

Cosas de Eclipse/Android

 

Ahora que estoy metiendome mucho más a desarrollar para Android (la verdad, no sé mucho…me estresa un poco la lentitud en la que aprendo…Java no es mi lenguaje favorito, todo gracias a horrendas experiencias en el pasado) pues estoy intentado aprender  resolver ciertos errores y advertencias que genera Eclipse.

Hoy por ejemplo,me aparecia:

 ActivityManager: Warning: Activity not started, its current task has been brought to the front

Seguro para los más versados en el tema, sabrán la solución. Pero yo, la n00b tuve que buscar qué demonios significaba eso…; con una simple búsqueda en Google entendí que ocurría. Pues que para que se pueda ejecutar el código se debe compilar primero, si  no se hace ningún cambio al código este no compila de forma automática y arroja esa advertencia.

Ahora ya sabes, toca el código, quita un espacio o …whatever.

Enjoy Android…

Share

Crash NSLayoutConstraint (funcionalidad de iOS 6)

Cuando nos toca actualizar cualquier SDK los valores añadidos de dicha actualización, muchas veces  generan problemas con programas realizados con el SDK anterior, bien sea porque hay líneas “Deprecated” u obsoletas, o porque hay que añadir alguna otra línea, funcionalidad, etc del API (los que usan Java viven esta tortura constantemente :p)

Así me ocurrió con la actualización de XCODE de 4.2 a 4.5 y que ahora usa iOS 6. Y aunque este post lo debí escribir hace mucho tiempo (2012 ya se fue) pues nunca es tarde para mencionar lo ocurrido.

Algunas nuevas funcionalidades de XCODE con iOS 6 es la utilización de Storyboards, es automático de hecho, y debería ser así. Sin embargo ya estaba a medio camino del proyecto cuando tuve que actualizar y no me di cuenta que las nuevas XIB que estaba creando me colocaban un “Check” en una opción que jamás había tocado antes. El AutoLayout.

¿Qué ocurre con esto? pensarás. Pues sencillo, cuando ejecutas tu programa en iOS 6 va de maravilla, puesto que ese AutoLayout es precisamente para iOS 6 y sus StoryBoards, si no usas StoryBoard no pasa nada. El problema aparece cuando bajas del iOS 6 al iOS 5 o 5.1 que NO es una funcionalidad de este sistema operativo y por lo tanto se cae al tratar de ejecutar el XIB con el AutoLayout marcado con el check y aparece el error de abajo:

1
*** Terminating app due to uncaught exception 'NSInvalidUnarchiveOperationException', reason: 'Could not instantiate class named NSLayoutConstraint'

La solución es sencilla: busca todos los XIB y desmarca la opción AUTOLAYOUT. ¡Presto!

Share

Depurando con DLog

Muchas veces, sino siempre, es necesario realizar depuraciones en nuestro código para determinar si hemos hecho las cosas bien o no, y básicamente para imprimir en la consola los valores que nos interesa observar. En Objective-C existe una forma, la tradicional de depurar que es usando la macro NSLog

1
NSLog(@"Bla blah");

NSLOG seguirá mostrando información en consola, aunque activemos la opción DEBUG (debug flag). Para evitar esto, existe la opción para debug llamada DLOG, que es otro macro que dejará de imprimir en consola cuando la bandera DEBUG este desactivada. De este modo, podremos dejar nuestros comentarios DLOG si desactivamos el modo debug.

Basta simplemente con hacer una cabecera (.h) (que yo llamare Macros.h) con el siguiente código:

1
2
3
4
5
6
7
8
9
#ifdef DEBUG

#define DLog(...) NSLog(@"%s %@", __PRETTY_FUNCTION__, [NSString stringWithFormat:__VA_ARGS__])

#else

#define DLog(...) do { } while (0)

#endif

y para usarlo en todo el proyecto, simplemente importalo al archivo

1
MyProjectExample-Prefix.pch

que se vería así

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//
// Prefix header for all source files of the 'ProjectExample' target in the 'ProjectExample' project
//

#import

#ifndef __IPHONE_4_0
#warning "This project uses features only available in iOS SDK 4.0 and later."
#endif

#ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import "Macros.h"
#endif

Ahora intenta emplearlo de la misma forma que con el NSLog. ¿Qué tal?

Dejo el código fuente para que lo veas mejor: aquí

Share

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í

 

¡He comenzado la app en Cocos2D!

 

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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#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;</div>

- (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).
1
2
self.notifyCenter = [NSNotificationCenter defaultCenter];
[notifyCenter addObserver:self selector:@selector(trackNotifications:) name:nil object:nil];
1. 2.- Se instancia una variable UIWindow
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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.
1
2
3
//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
1
2
3
4
5
6
//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

1
[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)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
- (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
1
2
3
4
5
6
7
8
#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
1
2
3
4
5
6
#import "uikit.h"

@interface PreJuego : UIViewController {
}
- (IBAction) empezarprueba: (id)sender;
@end
Este es el código dentro de PreJuego.m
1
2
3
- (IBAction) empezarprueba:(id)sender{
[[NSNotificationCenter defaultCenter] postNotificationName:@"empezarPrueba" object:@""];
}
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!
Share

Codemotion y Taller de Cocos2D

¡Hola!

Para iniciar el post debo agradecer a todos los asistentes al taller que impartí de Cocos2D en el gran evento Codemotion, de técnicos para técnicos. A pesar del calor y del error 404 a la hora de descargar el código (no podía dejar de haber algún fail en directo :P ) creo que ha sido una increíble experiencia, y satisfizo en todos los niveles mis expectativas. Los que han asistido al taller estaban muy interesados en el tema, y creo que salieron de el aún más interesados en el framework. Espero que a pesar del corto tiempo dedicado a la charla les haya servido de algo.

Y, pues nada, estoy super agradecida por los comentarios positivos y del apoyo de todos vosotros. Por eso ¡GRACIAS!.

Ahora, les dejo la presentación PPT y el código fuente del taller en Cocos2D. Recuerden que dentro (en el código fuente) está una guía que explica paso a paso cada parte del código, e igualmente si tenéis dudas no teman en contactarme bien sea por twitter o mail: phyonline[arroba]gmail[punto]com. Intentaré resolver sus dudas en lo que pueda.

Descarga Directa Código Fuente: http://t.co/lPRNbbUF 

Enlace a Medianet: http://www.medianet.es/1499/nuestros-companeros-en-codemotion/

¡Seguimos!

Share

NSDictionary Content

Gracias al  post de Nick Waynick, recordé como se puede hacer un NSLog del contenido de un diccionario JSON (aunque también debería funcionar para cualquier diccionario). Es el clásico código sencillo que olvidas cuando lo quieres usar. A ver si escribiéndolo aquí no lo olvido.

NSString *key;
for(key in jsonDictionary){
NSLog(@"Key: %@, Value %@", key, [jsonDictionary objectForKey: key]);
}
Share

NSDictionary to NSArray

 

Usually I write in spanish, but since this is a universal issue (at least for the people who code in objective-c) I’m going to post this “answer” in english.

I was struggling for a couple of hours with something that in the end was very simple, trying to put the values and keys of a NSDictionary in a NSArray to order them, I’m a N00b, yes. But that’s how we all started, so hopefully in some months I will be less N00bish. I was trying at first with this code:

 NSArray *array = [dictionary valueForKey:@"Root"]; 

But when I was iterating the array


for (int i=0;i<=[array count];i++)

{

NSDictionary *item = [array objectAtIndex:i];

}

The debugger send me a error message telling me that I was in fact wrong, and the NSDictionary can’t use the objectAtIndex. Wait, what? but it’s an array!!!  Well, I was telling the NSArray at the beging to work as a NSDictionary and I was unaware.

What I found out was that I needed to send all the values instead of using the valueForKey. And that was it. Solution served, easy indeed.

 NSArray *array = [dictionary allValues]; 
Share

Learning Cocoa

 

Puesto que tengo una memoria de pez, y la retentiva de un niño de 4 años  tengo que leer constantemente como hacer tal o cual cosa, pues me olvido con facilidad; aunque aprendo más rápido viendo a otros hacer, eso sí. Uno de los blogs que más he usado para programar en Objective-C han sido los siguientes:

http://cocoadevcentral.com/

 

Haz click en la imagen para ir al sitio

Share

Tutorial Configuración y Primeros Pasos: Panda3D+Crayon3D

 

 

Para una materia del master, realicé un tutorial de configuración y primeros pasos en Panda3D y Crayon 3D que pretendo compartir a continuación, para todo aquel que esté comenzando con dichas herramientas:

¿Qué es Panda3D?

Es un Game Engine o motor de videojuegos y un framework de renderizados 3D para programas en python y C++. Es de código abierto e incluye gráficos, audio, E/S, detección de colisiones y otra serie de características para la creación de juegos en 3D. Fue desarrollado por la Universidad Carnegie Mellon Entretainment Technolgy Center.

Enlace oficial: panda3d.org

¿Qué es Crayon3D?

Es una plataforma diseñada para usarse con Panda3D, permitiendo usar por ejemplo los Wiimotes y luces infrarrojas para Head Tracking. Es un proyecto creado por la Universidad Carnegie Mellon

Enlaces oficiales:

https://sites.google.com/site/crayon3d/
http://www.etc.cmu.edu/projects/crayon-3d/

 

Descargas

Tutorial Panda-Crayon3D

Descargar Proyecto

Tutorial de Instalación

Share

Publicación de iD-Stress en la App Store de Apple

¡Ya está aquí!

Publicada la versión 1.01 de iD-Stress  en la app store de Apple  y de la cual me siento bastante orgullosa. Sin embargo, no recibiré un centavo por la venta, ya que fue un proyecto de fin de Master…así que sólo obtengo publicidad y reconocimiento. Por algo se empieza.

Ahora sí, sin más preámbulos el enlace: ID-Stress en iTunes  

Además coloco el enlace de nuestra página web: Mediadome iD-Stress 

Share