
Olá pessoal! Antecipando o lançamento do curso
“iOS-developer. Curso básico ” , organizamos outra
lição aberta . Este seminário on-line foi desenvolvido para pessoas com experiência em desenvolvimento em qualquer idioma e plataforma, mas que desejam aprender a linguagem Swift e dominar o desenvolvimento para iOS. Na lição, examinamos detalhadamente a
sintaxe e as principais construções da linguagem Swift , familiarizando-nos com as principais ferramentas de desenvolvimento.
Os participantes do webinar aprenderam:
- qual é a linguagem Swift, quais são suas características;
- Como o ambiente de desenvolvimento do Xcode ajuda você a começar
- como criar um jogo simples para iOS.
O webinar foi conduzido por
Alexei Sobolevsky , desenvolvedor iOS da Yandex.
Faça você mesmo Snake
Para o trabalho, usamos o
ambiente de desenvolvimento integrado
Xcode . Este é um ambiente conveniente, gratuito e funcional criado pela Apple.
No começo, criamos um novo projeto e selecionamos o conjunto básico de arquivos "Jogo":

Sem mais delongas, eles chamaram o projeto de "Cobra". Todas as configurações foram deixadas por padrão, garantindo que o SpriteKit estivesse na linha de tecnologia de jogos.
Detalhes da criação do projeto.Após executar as ações acima, uma lista de arquivos criados automaticamente para o nosso projeto será exibida na parte esquerda da janela. Um dos arquivos mais importantes é o
AppDelegate.swift , que ajuda o sistema a se comunicar com o nosso código quando há eventos significativos para o aplicativo (iniciar, pressionar, clicar no link etc.). Código deste arquivo:
Arquivos igualmente importantes são
GameScene.swift e
GameViewController.swift . A classe GameScene cria a cena, e o GameViewController é responsável por uma tela do aplicativo que vemos (uma tela - uma GameViewController). Obviamente, essa regra nem sempre é suportada, mas geralmente funciona. Como nossa aplicação é bastante simples, teremos apenas um GameViewController. Vamos começar com ele.
Escrevendo um GameViewController
Vamos excluir o código padrão. O controlador de exibição possui vários métodos que funcionam, dependendo do estado da tela. Por exemplo,
viewDidLoad()
acionado quando todos os elementos da tela já foram carregados e a tela está prestes a aparecer no smartphone. Como temos um jogo, devemos colocar a cena do jogo em nosso controle de exibição (é aqui que a cobra irá correr e todos os outros eventos do jogo ocorrerão).
Crie uma cena:
let scene = GameScene(size: view.bounds.size)
let é uma constante e uma palavra-chave. Swift também usa a palavra-chave var, necessária para definir uma variável. Usando
var , podemos alterar o valor das variáveis várias vezes durante a execução do programa. Usando let, não podemos alterar o valor das variáveis após a inicialização.
Agora precisamos garantir que a exibição na qual colocaremos a cena criada corresponda ao tipo desejado. Para fazer isso, use a construção de
guarda - é o mesmo que
if
, apenas o contrário (se não):
guard let skView = view as? SKView else { return }
Depois de garantir que o elemento screen corresponda ao tipo desejado, adicionamos nossa cena a ele:
skView.presentScene(scene)
Você também precisa mostrar o número de quadros por segundo (FPS):
skView.showsFPS = true
Em seguida, exiba o número de elementos de todos os tipos em cena:
skView.showsNodeCount = true
E vamos fazer com que os elementos apareçam na tela, independentemente de sua ordem na hierarquia de elementos:
skView.ignoresSiblingOrder = true
E não esqueça que nossa cena deve ser esticada em toda a largura da tela:
scene.scaleMode = .resizeFill
Aqui está o código final para o arquivo
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) } }
Detalhes da criação do arquivo GameViewController.swift.Então, criamos a cena, mas ela está vazia; portanto, se rodarmos o emulador agora, veremos apenas uma tela preta.
Escrevendo um GameScene
Como na última vez, excluímos a maior parte do código e, em seguida,
executamos as configurações necessárias para a cena . Ele também tem seus próprios métodos. Por exemplo, como adicionamos nossa cena ao ViewController, precisamos do método
didMove()
:
override func didMove(to view: SKView) { setup(in: view) }
Além disso, quando o jogo começa, o método
Update()
é chamado para cada quadro:
override func update(_ currentTime: TimeInterval) { snake?.move() }
E também precisamos de alguns manipuladores para tocar na tela:
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 você sabe, Swift é famoso pela presença de
açúcar sintático . Açúcar sintático - esses são aspectos técnicos que simplificam a vida do desenvolvedor, aceleram a escrita do código. Tudo isso ajuda muito na montagem da cena, o que faremos agora. Antes de tudo, defina a cor:
backgroundColor = SKColor.white
Como a cobra trabalha em um avião, não precisamos de física, e você pode desativá-la para que a cobra não caia devido à gravidade. Além disso, não precisamos do jogo para girar, 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
Agora crie os botões:
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)
Ao escrever um pedaço de código, considere se o código pode ser aprimorado ou refatorado para poder ser
reutilizado no futuro. Olha, basicamente temos dois botões na tela, para a criação dos quais o mesmo código é usado. Portanto, esse código pode ser retirado em uma função separada. Para fazer isso,
crie uma nova classe e, consequentemente, o arquivo
ControlsFactory.swift com o seguinte 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 desenhar uma maçã aleatória que nossa cobra “comerá”,
crie a classe Apple e o arquivo
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 } }
E descrevemos nossa maçã com a função
createApple()
em
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) }
Bem, chegou a vez da cobra. Ele será composto de duas partes: o corpo (
SnakeBodyPart.swift ) e a cabeça (
SnakeHead.swift ).
Código
SiftBodyPart.swift :
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") } }
Código
SnakeHead.swift :
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") } }
No entanto, não incluiremos uma descrição de cada linha,
porque os detalhes da criação do arquivo GameScene.swift e outras classes são bem exibidos no vídeo. Oferecemos apenas para ver o código final do
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 } }
O resultado foi o jogo mais simples de Snake:

Demoramos cerca de uma hora e meia para escrever o jogo. Se você deseja obter habilidades de programação no Swift, repita todas as etapas você mesmo. A propósito,
aqui você terá acesso total a todos os arquivos de código que foram usados neste projeto.