Card3d with cocos2d

Vamos a crear un nuevo proyecto con el fin de renderizar cartas en 3D dentro de un proyecto cocos2d, todo esto queda fuera del alcance de cocos2d así que la finalidad del mismo será ver lo complicado que resulta sobrecargar los métodos necesarios para tomar el control de OpenGL para rotar un objeto y aplicarle luces.

El objetivo será crear un objeto con apariencia de carta en 3D para implementar el típico juego de buscar parejas:

Flip & flop

En un post anterior ya habiamos dibujado en 3D desde la nada y tampoco habia sido muy traumatico, recordemos que en el post Flip & Flop Part-1/ ya habiamos tratado algunos conceptos básicos de OpenGL para dibujar sprites con 2 caras y rotarlos para simular una carta.

Buscando por los foros de cocos2d podemos ver que existe una acción (CCOrbitCamera con un montón de parámetros extraños) para rotar los sprites sobre su eje Y (http://www.cocos2d-iphone.org/forum/topic/5074). El código viene a ser algo parecido a esto:

En este ejemplo creamos un sprite y le añadimos una acción llamada CCOrbitCamera haciendo que el Sprite rote 360 grados en su ejeY durante 5 segundos … luego ejecutamos la acción mediante un RepeatForever para que se quede ahí dando vueltas sin parar.

Solo le veo 2 problemas: El primero es que no se puede definir una textura para cada lado de la carta. La rotación se hace sobre un sprite y este se renderiza por los 2 lados igual ya que por defecto cocos2d no activa el CullFace. Si quieres tener una textura distinta al otro lado de la carta tienes que enlazar un evento y hacer la vuelta en 2 pasos para cambiar de forma manual la textura del sprite.

Y otra pega es que realmente no tiene apariencia 3D al no tener luces, y esto si que se convierte en un problema. Cocos2d no esta pensado para trabajar con luces así que los sprites no tienen normales, y por tanto aunque activemos la luz esta no va a calcular correctamente la incidencia de esta luz sobre el sprite que está girando.

Objetivos

Nuestro objetivo será crear una clase heredando toda la lógica de cocos2d y que nos permita corregir esos 2 problemas. Para ello vamos a crear estas un nuevo tipo de Sprite que implemente normales para hacer que la rotación tenga en cuenta las licens, y también crearemos una Acction para poder rotar la carta manteniendo la filosofía de acciones de cocos2d (que me parece genial).

  • CCSprite3D: Esta clase la heredaremos de CCSprite y solamente añadiremos las normales que no tiene la clase CCSprite de cocos2d, de esta forma al rotar el Sprite en el eje Y el calculo de la luz se hará correctamente:
  • Card3D: Esta clase la heredamos de CCNode para tener toda la lógica de los objetos de cocos2d, esta clase será la carta, tendrá definido las 2 caras de las cartas mediante Sprites3D y tendrá los metodos necesario para rotarlo en el eje Y.
  • CCFlipYLineal: Esta clase será una acción que podremos ejecutar sobre nuestra carta3D para rotar la carta y ponerla en la posición que nos interese. .. también estaría bien crear las 2 acciones con la rotación acelerada y decelerada.

CCSprite3D

Como hemos dicho esta clase hereda de CCSprite y añadiremos un array de flotantes para definir las normales de los vértices, si investigamos un poco la clase CCSprite vemos que dibuja el Sprite mediante un TriangleFan y que por tanto solo tiene 3 vértices para definirlo. El TriangleFan necesita 3 vertices para ser definido, pero OpenGL sabe que está renderizando un poligono cerrado y por tanto espera 4 vectores para las normales, por ello nuestra clase tendrá un array de 12 floats:

Nuestra clase proporcionará un nuevo método para definir cual es la normal del Sprite. Solo deberemos sobrecargar el método draw() para enviar a OpenGL nuestra normal y luego llamar al método draw() de la clase base para que siga dibujando el Sprite:

Y con esto ya tenemos una Clase heredada de CCSprite que añade esta nueva funcionalidad, lista para que la clase Card3D los use.

Card3D

Nuesta clase Card3D hereda de CCNode y solo tiene un float que define el angulo de rotación en Y.

Empezamos por el constructor, para seguir con la filosofia de cocos2d vamos a crear un método statico que lo inicializa y recibe como parámetro 2 imágenes. De momento este inicializador no es funcional ya que crea la carta con unas dimensiones fijas para las imágenes. Luego tendremos que crear más constructores para definir el sprite de la carta, pero de momento para hacer el test con esto es suficiente

Con estos 4 Sprites estamos creando una carta con esta apariencia:

A continuación tendremos que sobrecargar 2 métodos: En primer lugar el método Transform que es el que prepara la matriz antes de dibujar el objeto. En este método llamaremos al Transform de la clase padre para que haga las rotaciones, traslaciones y escalas propias de la lógica del CCNode y a continuación añadimos nosotros la rotación en el Eje Y

A continuación sobrecargamos el método draw, únicamente para activar los flags CullFace y Lighting de OpenGL. Activamos estos Flags, llamamos a su método visit (para que haga el visit de cada nodo interno que tenga) y posteriormente desactivamos los flags.

Con todo esto ya podemos ver lo fácil que resulta añadir funcionalidad a cocos2d con unos resultados mas que aceptables, aunque todavía nos faltaría arreglar algunas cosas para poder usar esta clase en un juego.
ala, fin!!!

Run Action

Ok .. ya tenemos nuestros Sprites en 3D, tenemos nuestra carta, y sabemos que teníamos un valor para rotarla … pero como he dicho antes la filosofía que tiene cocos2d de ejecutar acciones es sencillamente genial, así que vamos a crearnos una acción que nos haga la rotación de la carta:

Con todo esto para crear la carta y añadirla solo tendríamos que hacer esto:

Aquí tenéis el proyecto para verlo in person
 Card3D.zip (889.76 Kb)

ala, fin !!

Bueno .. fin no, queda explicar que este proyecto tiene todavía algunos conceptos que no me han quedado muy claros … la incidencia de la luz aun no está correctamente calculada, probablemente sea por la distancia de la luz al centro lógico de OpenGL … y otro detalle importante que no comprendo es porque las normales están en <1,0,0> y no en <0,0,1> … tendríamos que buscar como se inicializar la vista de OpenGL para comprender que orientación se está usando… son cosas que iremos depurando.

Ahora si, fin !!!

You may also like...

8 Responses

  1. homer0 dice:

    El comment no es sobre el post en si, pero te queria dejar dicho que me encanta el blog, cocos2d + tutoriales copados + español, no es que no me vaya el ingles, pero siempre es mas comodo en español 🙂

    Que no decaiga.

    Saludos

  2. gBeat dice:

    Excelente trabajo!!! Me guardo esta página en favoritos.
    ¿dónde puedo contactar contigo para hacerte una consulta? gracias por todo

  3. neofar dice:

    Gracias por los mensajes … cualquier consulta si es sobre el post por aqui va bien … intentaré contestar a todas si puedo.

    Un saludo

  4. moosc dice:

    Excelente tutorial!!
    Un par de sugerencias:
    – cuelgalo en los foros de cocos2d, le resultara util a mucha gente.

    – Cuelgalo en github.com : mucha gente podra ver tu codigo y mejorarlo, y si alguna vez este blog muere (esperemos que no) el codigo seguira vivo.

    – Mas mas mas… hacen falta este tipo de tutoriales, de nuevo: gracias!

    • neofar dice:

      gracias @moosc … tomo nota, ya he posteado alguna cosa en los foros de cocos2d .. el tema del github no me llega a gustar no es una herramienta que use y como ya tengo mi propio svn no necesito tener ningún repositorio publico, aunque sea con el fin de que la gente tenga el code .. para eso ya lo pongo aquí, y hombre .. espero que el blog no muera

  5. Yotam dice:

    great sample and lesson!!!
    i wanted to know if there is a problem with sprites at the edges/borders of the screen? when i move the sprite’s position to corners , the rotation looks distorted .

    thanx!!

  6. Douglas13062 dice:

    hola, mira necesito ayuda, soy nuevo en el uso de cocos2d, y pues la verdad deceo hacer un pequeño juego de parejas, pero no encuentro como hacer para seleccionar ambas imagenes, no se si me podrias ayudar, te lo agradeceria mucho

  1. 6 enero, 2012

    […] Card3d – object with 3D chart appearance: LINK […]

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos necesarios están marcados *