
Hola a todos! En previsión del lanzamiento del curso
"iOS-developer. Curso básico ” organizamos otra
lección abierta . Este seminario web está diseñado para personas que tienen experiencia en el desarrollo en cualquier idioma y plataforma, pero desean aprender el lenguaje Swift y dominar el desarrollo para iOS. En la lección, examinamos en detalle la
sintaxis y las construcciones clave del lenguaje Swift , nos familiarizamos con las principales herramientas de desarrollo.
Los participantes del seminario web aprendieron:
- cuál es el lenguaje Swift, cuáles son sus características;
- Cómo el entorno de desarrollo de Xcode te ayuda a comenzar
- Cómo crear un juego simple para iOS.
El seminario web fue realizado por
Alexei Sobolevsky , un desarrollador de iOS en Yandex.
Hazlo tu mismo Snake
Para el trabajo, utilizamos el
entorno de desarrollo integrado
Xcode . Este es un entorno conveniente, gratuito y funcional creado por Apple.
Al principio, creamos un nuevo proyecto y seleccionamos el conjunto básico de archivos de "Juego":

Sin más preámbulos, llamaron al proyecto "Serpiente". Todas las configuraciones se dejaron de forma predeterminada, asegurándose de que SpriteKit estuviera en la línea Game Technology.
Detalles de la creación del proyecto.Después de realizar las acciones anteriores, se mostrará una lista de archivos creados automáticamente para nuestro proyecto en la parte izquierda de la ventana. Uno de los archivos más importantes es
AppDelegate.swift , que ayuda al sistema a comunicarse con nuestro código cuando hay eventos importantes para la aplicación (inicio, inserción, clic en el enlace, etc.). Código de este archivo:
Archivos igualmente importantes son
GameScene.swift y
GameViewController.swift . La clase GameScene crea la escena, y GameViewController es responsable de una pantalla de la aplicación que vemos (una pantalla, una GameViewController). Por supuesto, esta regla no siempre es compatible, pero en general funciona. Como nuestra aplicación es bastante simple, solo tendremos un GameViewController. Comencemos con él.
Escribir un GameViewController
Eliminaremos el código predeterminado. El controlador de vista tiene varios métodos que funcionan según el estado de la pantalla. Por ejemplo,
viewDidLoad()
activa cuando todos los elementos de la pantalla ya se han cargado y la pantalla está a punto de aparecer en el teléfono inteligente. Como tenemos un juego, necesitamos colocar la escena del juego en nuestro controlador de vista (aquí es donde se ejecutará la serpiente y ocurrirán todos los demás eventos del juego).
Crea una escena:
let scene = GameScene(size: view.bounds.size)
let es una constante y una palabra clave. Swift también usa la palabra clave var, que es necesaria para definir una variable. Usando
var , podemos cambiar el valor de las variables muchas veces mientras se ejecuta el programa. Usando let, no podemos cambiar el valor de las variables después de la inicialización.
Ahora debemos asegurarnos de que la vista en la que colocaremos la escena creada corresponda al tipo deseado. Para hacer esto, use la construcción de
guardia : esto es lo mismo que
if
, solo al revés (si no):
guard let skView = view as? SKView else { return }
Después de asegurarnos de que el elemento de pantalla coincida con el tipo deseado, le agregamos nuestra escena:
skView.presentScene(scene)
También debe mostrar la cantidad de fotogramas por segundo (FPS):
skView.showsFPS = true
Luego muestre el número de elementos de todos los tipos en la escena:
skView.showsNodeCount = true
Y hagamos que los elementos aparezcan en la pantalla independientemente de su orden en la jerarquía de elementos:
skView.ignoresSiblingOrder = true
Y no olvide que nuestra escena debe extenderse a todo el ancho de la pantalla:
scene.scaleMode = .resizeFill
Aquí está el código final para el archivo
GameViewController.swift :
import UIKit import SpriteKit import GameplayKit class GameViewController: UIViewController { override func viewWillLayoutSubviews() { super.viewWillLayoutSubviews() setup() } private func setup() { guard let skView = view as? SKView else { return } let scene = GameScene(size: view.bounds.size) skView.showsFPS = true skView.showsNodeCount = true skView.ignoresSiblingOrder = true scene.scaleMode = .resizeFill skView.presentScene(scene) } }
Detalles de la creación del archivo GameViewController.swift.Entonces, creamos la escena, pero está vacía, así que si ejecutamos el emulador ahora, solo vemos una pantalla en negro.
Escribir una escena de juego
Como la última vez, eliminamos la mayor parte del código y luego
realizamos los ajustes necesarios para la escena . También tiene sus propios métodos. Por ejemplo, dado que agregamos nuestra escena al ViewController, necesitamos el método
didMove()
:
override func didMove(to view: SKView) { setup(in: view) }
Además, cuando comienza el juego, se llama al método
Update()
para cada cuadro:
override func update(_ currentTime: TimeInterval) { snake?.move() }
Y también necesitamos algunos controladores para tocar la pantalla:
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { guard let touchedNode = findTouchedNode(with: touches) else { return }
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) { guard let touchedNode = findTouchedNode(with: touches) else { return }
Como saben, Swift es famoso por la presencia de
azúcar sintáctica . Azúcar sintáctico: estos son aspectos técnicos que simplifican la vida del desarrollador y aceleran la escritura del código. Todo esto ayuda mucho en la configuración de la escena, lo que vamos a hacer ahora. En primer lugar, configure el color:
backgroundColor = SKColor.white
Dado que la serpiente trabaja en un avión, no necesitamos física, y puede apagarla para que la serpiente no se caiga debido a la gravedad. Además, no necesitamos que el juego gire, etc.
physicsWorld.gravity = .zero physicsWorld.contactDelegate = self physicsBody = SKPhysicsBody(edgeLoopFrom: frame) physicsBody?.allowsRotation = false physicsBody?.categoryBitMask = CollisionCategories.edgeBody physicsBody?.collisionBitMask = CollisionCategories.snake | CollisionCategories.snakeHead view.showsPhysics = true
Ahora crea los botones:
let counterClockwiseButton = ControlsFactory.makeButton(at: CGPoint(x: scene.frame.minX + 30, y: scene.frame.minY + 50), name: .counterClockwiseButtonName) addChild(counterClockwiseButton) let clockwiseButton = ControlsFactory.makeButton(at: CGPoint(x: scene.frame.maxX - 90, y: scene.frame.minY + 50), name: .clockwiseButtonName) addChild(clockwiseButton)
Cuando haya escrito un fragmento de código, debe considerar si el código puede mejorarse o refactorizarse para que pueda
reutilizarse en el futuro. Mira, básicamente tenemos dos botones en la pantalla, se usa el mismo código para crearlos. Entonces, este código puede eliminarse en una función separada. Para hacer esto,
cree una nueva clase y, en consecuencia, el archivo
ControlsFactory.swift con el siguiente código:
import SpriteKit final class ControlsFactory { static func makeButton(at position: CGPoint, name: String) -> SKShapeNode { let button = SKShapeNode() button.path = UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: 45, height: 45)).cgPath button.position = position button.fillColor = .gray button.strokeColor = UIColor.lightGray.withAlphaComponent(0.7) button.lineWidth = 10 button.name = name return button } }
Para dibujar una manzana aleatoria que nuestra serpiente "comerá",
cree la clase Apple y el archivo
Apple.swift :
import SpriteKit final class Apple: SKShapeNode { let diameter: CGFloat = 10 convenience init(at point: CGPoint) { self.init() path = UIBezierPath(ovalIn: CGRect(x: -diameter/2, y: -diameter/2, width: diameter, height: diameter)).cgPath fillColor = .red strokeColor = UIColor.red.withAlphaComponent(0.7) lineWidth = 5 position = point physicsBody = SKPhysicsBody(circleOfRadius: diameter / 2, center: .zero) physicsBody?.categoryBitMask = CollisionCategories.apple } }
Y describimos nuestra manzana con la función
createApple()
en
GameScene.swift :
private func createApple() { let padding: UInt32 = 15 let randX = CGFloat(arc4random_uniform(UInt32(gameFrameRect.maxX) - padding) + padding) let randY = CGFloat(arc4random_uniform(UInt32(gameFrameRect.maxY) - padding) + padding) let apple = Apple(at: CGPoint(x: randX, y: randY).relative(to: gameFrameRect)) gameFrameView.addChild(apple) }
Bueno, ha llegado el turno de la serpiente. Constará de dos partes: el cuerpo (
SnakeBodyPart.swift ) y la cabeza (
SnakeHead.swift ).
SnakeBodyPart.swift Code:
import SpriteKit class SnakeBodyPart: SKShapeNode { init(at point: CGPoint, diameter: CGFloat = 10.0) { super.init() path = UIBezierPath(ovalIn: CGRect(x: -diameter/2, y: -diameter/2, width: diameter, height: diameter)).cgPath fillColor = .green strokeColor = UIColor.green.withAlphaComponent(0.7) lineWidth = 5 position = point physicsBody = SKPhysicsBody(circleOfRadius: diameter - 4, center: .zero) physicsBody?.isDynamic = true physicsBody?.categoryBitMask = CollisionCategories.snake physicsBody?.contactTestBitMask = CollisionCategories.edgeBody | CollisionCategories.apple } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } }
SnakeHead.swift Code:
import SpriteKit final class SnakeHead: SnakeBodyPart { init(at point: CGPoint) { super.init(at: point, diameter: 20) physicsBody?.categoryBitMask = CollisionCategories.snakeHead physicsBody?.contactTestBitMask = CollisionCategories.edgeBody | CollisionCategories.apple } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } }
Sin embargo, no lo aburriremos con una descripción de cada línea,
porque los detalles de la creación del archivo GameScene.swift y otras clases se muestran bien en el video. Solo ofrecemos ver el código final de
GameScene.swift :
import SpriteKit import GameplayKit class GameScene: SKScene { var gameFrameRect: CGRect = .zero var gameFrameView: SKShapeNode! var startButton: SKLabelNode! var stopButton: SKLabelNode! var snake: Snake? override func didMove(to view: SKView) { setup(in: view) } override func update(_ currentTime: TimeInterval) { snake?.move() } override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { guard let touchedNode = findTouchedNode(with: touches) else { return } if let shapeNode = touchedNode as? SKShapeNode, touchedNode.name == .counterClockwiseButtonName || touchedNode.name == .clockwiseButtonName { shapeNode.fillColor = .green if touchedNode.name == .counterClockwiseButtonName { snake?.moveCounterClockwise() } else if touchedNode.name == .clockwiseButtonName { snake?.moveClockwise() } } else if touchedNode.name == .startButtonName { start() } else if touchedNode.name == .stopButtonName { stop() } } override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { guard let touchedNode = findTouchedNode(with: touches) else { return } if let shapeNode = touchedNode as? SKShapeNode, touchedNode.name == .counterClockwiseButtonName || touchedNode.name == .clockwiseButtonName { shapeNode.fillColor = .gray } } override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) { guard let touchedNode = findTouchedNode(with: touches) else { return } if let shapeNode = touchedNode as? SKShapeNode, touchedNode.name == .counterClockwiseButtonName || touchedNode.name == .clockwiseButtonName { shapeNode.fillColor = .gray } }
El resultado fue el juego de serpiente más simple:

Nos llevó aproximadamente una hora y media escribir el juego. Si desea adquirir habilidades de programación en Swift, repita todos los pasos usted mismo. Por cierto,
aquí obtendrá acceso completo a todos los archivos de código que se utilizaron en este proyecto.