() translation by (you can also view the original English article)






En ésta serie, te enseñaré como crear unos Invasores del Espacio inspirados en el juego usando Sprite Kit y el lenguaje de programación Swift. A lo largo del camino, aprenderás sobre el motor de física integrado de Sprite Kit, generar partículas usando el editor de partículas integrado de Sprite Kit, usar el acelerómetro para mover el jugador y mucho más. Comencemos.
Introduciendo Sprite Kit
Sprite Kit es el motor de juegos 2D de Apple que fue introducido con iOS 7. Con la introducción del lenguaje de programación Swift en el 2014, nunca hubo un mejor tiempo para ser un desarrollador de juegos para iOS.
Sprite Kit proporciona un motor de renderizado construido sobre el estándar gráfico OpenGL. Con el uso de sprites con texturas, un motor de física integrado, y la muy poderosa clase SKAction, puedes crear muy rápidamente juegos 2D funcionales.
Bucle de Renderizado
Sprite Kit, como la mayoría de los motores de juego, utiliza un bucle para renderizar y actualizar la pantalla. El bucle de renderizado tiene varios pasos que cubre antes de renderizar la escena actual. Son los siguientes:
- Actualizar
- Evaluar acciones
- Simular física
- Aplicar restricciones
- Renderizar la escena
Cada uno de éstos tiene un método correspondiente que puedes usar para aplicar cualquier lógica adicional que necesita realizarse en ese tiempo dentro del marco. Específicamente, usarías los siguientes métodos dentro de la escena.
update
didEvaluateActions
didSimulatePhysics
didApplyConstraints
didFinishUpdate
Estamos interesados en dos de éstos métodos para éste tutorial, update y didSimulatePhysics. Usaremos el método update para mover a los invasores manualmente y el método didSimulatePhysics para actualizar al jugador, que será controlado usando el acelerómetro y el motor de física.
SKNode
Uno de los bloques que conforman el framework Sprite Kit es la clase SKNode. La clase SKNode no genera ningún recurso visual. Su papel principal es proporcionar un comportamiento base que implementan otras clases. La clase SKScene es el nodo raíz en un árbol de instancias SKNode y es usada para albergar sprites y otro contenido que necesita ser renderizado.
El renderizado y la animación se hacen por una instancia SKScene que se coloca dentro de una ventana y otras vistas son añadidas a élla después. La instancia SKScene se añade a la instancia SKView. Puedes usar una sola instancia SKView en tu ventana y cambiar entre diferentes escenas en cualquier momento.
El framework define un número de subclases de SKNode. La más común para crear una escena es la clase SKSpriteNode. La clase SKSpriteNode puede ser dibujada como un rectángulo con SKTexture contenido en ella, o como un rectángulo con textura y color. Con frecuencia usarás sprites con textura, porque es así como tu trabajo cobra vida en tu juego. Checa el árbol de herencia de la clase SKNode para ver que otros tipos de nodos están disponibles.
SKAction
La clase SKAction es lo que dan vida a tus clases SKNode. Al usar la clase SKAction puedes mover, rotar, escalar y desvanecer los nodos. También puedes usar SKAction para reproducir un sonido y ejecutar código. La clase SKAction es muy poderosa, y junto con la clase SKNode, es uno de los bloques que conforman un juego de Sprite Kit.
Motor de Fisica
Sprite Kit tiene un motor de física integrado que hace muy fácil el manejo de situaciones físicas complejas. Si alguna vez has tratado de implementar un motor de física por tí mismo, apreciarás ésta característica.
En Sprite Kit, la coordenada (0,0) se localiza en la parte inferior izquierda de la pantalla en lugar de la parte superior izquierda, como podrías estar acostumbrado si has trabajado con Flash, Corona, HTML5 Canvas, y muchos otros frameworks para juegos. Ésto es porque Sprite Kit utiliza OpenGL bajo la máscara.
Te sugiero ampliamente leer la Guía de Programación para Sprite Kit de Apple para familiarizarte más con los conceptos mencionados anteriormente. Dejando atrás ésta breve introducción, comencemos a construir un juego con Sprite Kit.
1. Establecer el Proyecto
Abre Xcode y elige Create a new Xcode project ó elige New>Project.. del menu File.



Asegúrate de que tu target sea iOS, que el tipo sea Application, y que hayas elegido Game como tu tipo de plantilla. Haz click en Next para continuar.



Posteriormente elige cualquier cosa que quieras para Product Name (Nombre del Producto),Organization Name (Nombre de la organización), y Identifier Organization (Identificador de la Organización). No olvides establecer Language a Swift, Game Technology a Sprite Kit, y Devices a iPad. Especifica una ubicación para guardar los archivos del proyecto y da click en Create.



Si das click para ejecutar el botón en la parte superior izquierda (o presionas Command-R), Xcode compilará y ejecutará tu aplicación, mostrando el texto "Hello, World). Cuando pulses la pantalla, se agregará una imagen de una nave espacial y comenzará a rotar.



2. Configuración del Proyecto
Selecciona el Proyecto en el Project Navigator y abre la pestaña General en la parte superior. En Deployment Info, desmarca todas las casillas de verificación menos Portrait en Device Orientation.



Después, selecciona y borra GameScene.sks. El archivo .sks te permite conformar la escena visualmente. Para éste proyecto, estaremos añadiendo cada nodo programáticamente. Abre GameViewController.swift, borra su contenido, y remplázalo con lo siguiente.
1 |
import UIKit |
2 |
import SpriteKit |
3 |
|
4 |
class GameViewController: UIViewController { |
5 |
|
6 |
override func viewDidLoad() { |
7 |
super.viewDidLoad() |
8 |
let scene = StartGameScene(size: view.bounds.size) |
9 |
let skView = view as SKView |
10 |
skView.showsFPS = true |
11 |
skView.showsNodeCount = true |
12 |
skView.ignoresSiblingOrder = true |
13 |
scene.scaleMode = .ResizeFill |
14 |
skView.presentScene(scene) |
15 |
}
|
16 |
|
17 |
override func prefersStatusBarHidden() -> Bool { |
18 |
return true |
19 |
}
|
20 |
}
|
La clase GameViewController hereda de UIViewController y tendrá un SKView como su vista. Dentro el método viewDidLoad, transformamos su propiedad view a una instancia SKView y la configuramos.
Puedes haber notado el texto en la esquina inferior derecha de la pantalla cuando ejecutaste la aplicación por primera vez. Para eso son las propiedades showsFPS y showsNodeCount, mostrando el número de cuadros por segundo a los que el juego se ejecuta y el número de SKNodes visibles en la escena.
Si alguno de los nodos se moviera fuera de la pantalla, la cuenta del nodo bajaría, pero continuarían en la memoria. Ésto es importante para recordar y no permitas que la cuenta del nodo te engañe. Si sumas 100 nodos a una escena y 90 de ellos están fuera de la pantalla, aún tienes 100 nodos ocupando la memoria.
Para propósitos de optimización, el ignoresSiblingerOrder se establece a true. Puedes leer más sobre ésto en la Guía de Programación para Sprite Kit. Lo último que hacemos es invocar al método presentScene de SKView y pasarlo en en StartGameScene, que creará el próximo paso.
Finalmente, no queremos que se muestre la barra de estado así que regresamos true del método preferStatusBarHidden.
3. Creando StartGameScene
Paso 1:Añadiendo la clase StartGameScene
Elige New>File... del menú File y elige Cocoa Touch Class de la sección iOS>Soure. Da click en Next para continuar.



Posteriormente, nombra la clase StartGameScene y asegúrate de que hereda de SKScene. Language debería establecerse a Swift. Da click en Next para continuar.



Especifica a Xcode donde te gustaría guardar el archivo para la nueva clase y da click en Create. Agrega el siguiente código a StartGameScene.swift.
1 |
import UIKit |
2 |
import SpriteKit |
3 |
class StartGameScene: SKScene { |
4 |
|
5 |
override func didMoveToView(view: SKView) { |
6 |
backgroundColor = SKColor.blackColor() |
7 |
NSLog("We have loaded the start screen") |
8 |
}
|
9 |
}
|
El método didMoveToView(_:) es llamado inmediatamente despues de que la escena es presentada por la vista. Generalmente, aquí es donde harás la configuración para tu escena y crearás tus recursos.
i pruebas el juego ahora deberías observar una pantalla negra que muestra el número de cuadros por segundo que está reproduciendo el juego y la cuenta de nodo en la esquina inferior derecha de la pantalla.
Paso 2: Añadiendo startGameButton
No es divertido mirar una pantalla negra así que vamos a crear nuestra primera instancia SKSpriteNode Actualiza el método didMoveToView(_:) como se muestra abajo.
1 |
override func didMoveToView(view: SKView) { |
2 |
let startGameButton = SKSpriteNode(imageNamed: "newgamebtn") |
3 |
startGameButton.position = CGPointMake(size.width/2,size.height/2 - 100) |
4 |
startGameButton.name = "startgame" |
5 |
addChild(startGameButton) |
6 |
}
|
Declaramos una constante startGameButton usando el conveniente inicializador init(imageNamed:), que tomar como argumento el nombre de la imagen. La centramos en la pantalla tanto horizontal como verticalmente, excepto que restamos 100 puntos para colocarla un poco fuera del centro del eje vertical. Establecemos su propiedad name a startgame así podemos ubicarla después. Finalmente, la añadimos a la escena al invocar addChild(_:), que toma como argumento el nodo para añadir a la escena. Puedes aprender más sobre la clase SKSpriteNode en la Guía deReferencia del Framework Spritekit.
Ahora sería un buen momento para agregar las imágenes al proyecto. Descarga los archivos fuente de éste tutorial y busca el directorio llamado images. Arrástralo al directorio que tiene el nombre de tu proyecto, por ejemplo, Mobile TutsInvaderz. Asegúrate de que esté marcado Copy items if needed así como el target principal en la lista de targets.



Si pruebas tu aplicación, deberás ver un boton con la etiqueta "New Game".



Paso 3: Implementando touchesBegan
Luego, necesitamos implementar el método touchesBegan(_:withEvent:). Su implementación se muestra abajo. El método touchesBegan es invocado cuando uno o más dedos tocan la pantalla.
1 |
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) { |
2 |
for touch: AnyObject in touches { |
3 |
let touchLocation = touch.locationInNode(self) |
4 |
let touchedNode = self.nodeAtPoint(touchLocation) |
5 |
if(touchedNode.name == "startgame"){ |
6 |
let gameOverScene = GameScene(size: size) |
7 |
gameOverScene.scaleMode = scaleMode |
8 |
let transitionType = SKTransition.flipHorizontalWithDuration(1.0) |
9 |
view?.presentScene(gameOverScene,transition: transitionType) |
10 |
}
|
11 |
}
|
12 |
}
|
La propiedad multiTouchEnabled de la vista de la escena es establecida a false por defecto, lo que significa que la vista sólo recibe el primer toque de una sequencia multitouch (toques múltiples). Con esta propiedad deshabilitada, puedes recuperar el toque al llamar a AnyObject en la serie touches pues sólo hay un objeto en la serie.
Guardamos la ubicación del toque en la escena en una constante llamada touchLocation. Hacemos ésto al invocar locationInNode(_:) en el objeto touch, pasando la escena. Podemos entonces determinar que nodo fue tocado al invocar nodeAtPoint, pasando la ubicación del toque. Con éste nodo toucheNode encontrado, podemos revisar la propiedad name y, si es igual a startgame, sabemos que ellos pulsaron el botón.
Si el usuario pulsó el botón, hacemos una instancia de la clase GameScene y establecemos su scaleMode similar al modo de escala de la escena actual. Entocnes creamos un SKTransition llamado transitionType y mostramos la escena al invocar presentScene(:_transition) pasando el gameOverScene y el transitionType.
Hay pocos tipos SKTransition para escoger. Puedes leer más sobre ellos en la Guía de Referencia del Framework SpriteKit. Te sugiero que pruebes algunos y veas cuáles te gustan más.
i pruebas tu aplicación, puedes pulsar el botón, que te lleva a GameScene. Ésta es la misma escena con la que inició el proyecto.
Conclusión
Esto concluye la primera parte de ésta serie. Te has iniciado en Sprite Kit y has aprendido como crear escenas, utilizar la clase SKSpriteNode, y detectar toques. Ésto es sólo el principio, todavía tenemos mucho que aprender. Gracias por leer y nos vemos en la próxima parte de ésta serie.
¡Sé el primero en conocer las nuevas traducciones–sigue @tutsplus_es en Twitter!