mundial

Un vistazo a SpriteKit con Swift por @zjorge

Código fuente de la App de Ejemplo

Apenas minutos después del anuncio de la llegada de Swift en el WWDC 2014 ya se sentía en el Moscone Center una mezcla de duda, pánico y entusiasmo.  Creo que mi sentimiento era de duda pues con lo poco que conozco de Objective C y de programación en general no sufro el pánico por lo conocido en ObjC pero tampoco entiendo el entusiasmo promovido por Craig con las nuevas características de Swift. Para poder evaluar realmente las ventajas o desventajas de Swift mi mejor opción es simplemente experimentar.

Hasta ahora mi experiencia para gráficos 2D ha sido con Cocos2D usando SpriteBuilder para el montaje de las escenas y TexturePacker para preparar los sprite sheets.  Me pareció una buena idea aprovechar mis experimentos con Swift e integrar SpriteKit, principalmente para probar lo de per pixel collision.

Comencemos creando un nuevo proyecto en XCode 6.  Como template vamos a elegir las opciones iOS -> application y Game.  Luego le colocamos nombre y definimos Swift como language y como Game Technology utilizaremos SpriteKit.

Captura de pantalla 2014-07-10 09.39.27

Captura de pantalla 2014-07-10 09.39.59

Limitemos en este caso la orientación a las opciones Landscape derecha e izquierda.  Aunque la opción de cambiar la versión de iOS no está deshabilitada, este tutorial no funciona con versiones anteriores a iOS 8.0 por lo que debe quedar Deployment Target en 8.0 y en caso de probarlo en un dispositivo éste debe tener instalado iOS 8 también.

Captura de pantalla 2014-07-10 09.52.13  Captura de pantalla 2014-07-10 09.44.30

Este template tiene, además de las imágenes, los archivos de soporte y las carpetas de test y productos cinco archivos. Tres son swift, un storyboard y una escena.  En este tutorial sólo vamos a agregar imágenes y editar los archivos GameScene.swiftGameScene.sks y GameViewController.swift.  En  GameScene.swift borremos el contenido de las funcion didMoveToView  y en touchesBegan  borramos lo que está dentro del for  para quedar así:

La primera línea que vamos a colocar simplemente va a guardar en location la posiciones para cada contacto en la pantalla.

El punto y coma es completamente opcional pero después de años de PHP, JavaScript y ObjC se me hace automático colocarlo. Para poder ver en la cosola y comprobar que algo está sucediendo agreguemos la siguiente línea:

Es hora de compilar!  Mi recomendación es hacerlo en un dispositivo en vez del simulador.  En el dispositivo podemos probar multitoques y manipular la aplicación tal cual lo haría el usuario.  Una vez inicia la aplicación y hagamos algunos toques en la pantalla debemos ver en la consola algo así:

Hasta ahora, aunque sí estamos cargando la escena definida en GameScene.sks, no hemos escrito nada que utilice SpriteKit.  Arrastremos los archivos de imagen guanabara.jpg, redentor.png y brazuca_mini.png a la carpeta Supporting Files y luego, agreguemos  touchesBegan  las siguientes líneas:

Si compilamos ahora podemos ver que al correr la aplicación, para cada toque en la pantalla, además de imprimir las coordenadas en la consola veremos también una brazuca en la pantalla.

image1

Todas quietas, sin gravedad, sin impulso, sin efecto de fricción, sin posibilidad de gol.  Vamos a agregarle algo de física.  Justo antes de addChild  colocamos:

Aquí lo único que estamos haciendo es darle al sprite un cuerpo y diciéndole a este cuerpo que responde a propiedades físicas como gravedad y colisiones. Probemos que sucede ahora (cmd + b).  Al correr la aplicación notamos que ahora la gravedad hace caer los balones y si los dejamos tocar podemos ver que obedecen también a las colisiones entre ellos.  Es un poco difícil lograr una colisión si no tenemos un piso que detenga la caída así que agregaremos uno.  Para eso vamos a agregar la siguiente función:

Con esta función podemos agregar sólidos rectangulares fijos en cualquier punto de la pantalla (o fuera de ella).  Probemos llamando la función agregando a didMoveToView  las dos líneas a continuación:

Ahora tenemos un cuerpo sólido de 20 x 200 colocado en el punto 100,100 pero el sólido es invisible.

image6

Podemos notar su presencia si tiramos muchos balones en el lado izquierdo de la pantalla pero es mucho mejor, para poder entender que está sucediendo, utilizar la ayuda que nos brinda SKView con la propiedad showsPhysics . Vamos a abrir el archivo GameViewController.swift y dentro de viewDidLoad , luego de showsFPS  y showsNodeCount , agregamos skView.showsPhysics = true  para tener algo así:

Si compilamos ahora podemos demostrar nuestra destreza con el balón equilibrándolo sobre una pared invisible.

Ahora pongamos un escenario propicio para estos balones. Vamos a abrir GameScene.sks y primero cambiamos el ancho y alto de la escena en el panel de utilities a 576 x 320 como indica la imagen.

Captura de pantalla 2014-07-10 13.43.30

Ahora arrastramos desde la carpeta Supporting Files el archivo guanabara.jpg y lo dejamos caer en el centro de la escena. Asegurémonos que la imagen (node) está seleccionada y ajustemos la posición según vemos en la captura de pantalla.

Captura de pantalla 2014-07-10 17.11.29

Este es un fondo estático.  No va a tener ninguna influencia sobre la dinámica de los balones y tampoco recibirá los efectos de la gravedad en la escena. Por esta razón tenemos que ajustar sus propiedades físicas a Body Type: none.

Captura de pantalla 2014-07-10 17.39.08

Vamos a agregar ahora otro nodo, agreguemos al Cristo Redentor arrastrando el archivo redentor.png a la escena.  Ajustemos la posición como lo indica la imagen y probemos la aplicación ahora.

Captura de pantalla 2014-07-10 17.19.58

Vemos que los toques envían sus coordenadas a la consola pero es posible que los balones no se estén creando.  En realidad si están siendo creados pero están detrás de fondo.  Hagamos un pequeño ajuste para corregir esto. En GameScene.sks seleccionamos el nodo donde está la imagen de fondo y en panel de propiedades verifiquemos que zPosition está en 0, luego en GameScene.swift asignemos al balón creado un zPosition = 10  para asegurarnos de que vaya a quedar frente al fondo.

Probemos nuevamente y vemos como los balones caen frente al paisaje y chocan con el redentor cuando caen sobre ese nodo.  El problema aquí es que el nodo es rectangular y no interactúa como esperado con los balones.  Para lograr colisiones más precisas sería necesario desglosar la forma del redentor en partes más sencillas y unirlas o crear un polígono complejo pero aún así los resultados probablemente sería aproximados.

image5

Para resolver esto ahora tenemos “per-pixel collision”, un método de cálculo de colisiones que utiliza el canal alpha para determinar el borde del sólido.  Hay que resaltar que este método consume muchos más recursos que los rectangulares o circulares, usar con moderación.

image4

Si quieres dejar tu aplicación algo más presentable puedes comentar las líneas auxiliares SKView en GameViewController.swift función viewDidLoad :

Ahora podemos ver al redentor haciendo ciertos trucos con las brazucas.  Nada que evite un 7 a 1 desafortunadamente.

image1 (1)

Al comparar Swift con Objective-C en algo sencillo como esto no veo mucha diferencia, de hecho rápidamente olvido que no es Objective-C pues al trabajar con SpriteKit la sintaxis es bastante similar.  Puede que la razón de esto es que aún abordamos todo a la ObjC y dejamos de ver o aprovechar ventajas propias de Swift.  Creo que, como dice mi mujer, “amanecerá y veremos”.

Código fuente de la App de Ejemplo

Acerca de Jorge Ledezma

Panameño nacido en Madrid, Jorge Ledezma es arquitecto y pseudo programador solucionando bugs con metodología vudú desde 1982.

Share this:

Leave a comment