Advertisement
  1. Code
  2. iOS

SpriteKit From Scratch: Efeitos visuais e de áudio

Scroll to top
This post is part of a series called SpriteKit From Scratch.
SpriteKit From Scratch: Physics and Collisions
SpriteKit From Scratch: Advanced Techniques and Optimizations

Portuguese (Português) translation by David Batista (you can also view the original English article)

Introdução

Neste tutorial, a quarta parte da série SpriteKit From Scratch, vamos dar uma olhada em vários recursos visuais e de áudio que o SpriteKit fornece para adicionar mais detalhes e variedades para seu jogo. Isso inclui sistemas de partícula, filtros, luz e áudio.

Para me seguir, você pode usar o projeto criado no tutorial anterior desta série ou baixar uma nova cópia no GitHub.

As imagens usadas pra o jogo desta série podem ser encontradas no GraphicRiver. O GraphicRiver é uma ótima fonte para encontrar trabalhos artísticos e imagens para seus jogos.

1. Sistemas de partícula

No SpriteKit, o termo sistema de partícula se refere á um único nó emissor, representado pela classe SKEmitterNode. Ele define a posição do sistema na sua cena e todas as partículas que ele cria. O emissor especifica os vários comportamento das partículas que ele gera.

O sistema de partícula é melhor usado nos jogos em SpriteKit quando você precisa gerar uma grande quantidade de sprites idênticos ou similares, que não precisam ter uma localização específica ou executar alguma ação.

Neste tutorial, iremos adicionar dois sistemas de partícula quando o carro acertar um obstáculo:

  • um pequeno efeito de explosão que aparece brevemente
  • um efeito de fumaça que permanece indefinidamente na cena

Apesar dos sistemas de partícula poderem ser criados via programação, é muito mais fácil cria-los usando o editor do Xcode. Todas as propriedades de um sistema de partícula podem ser modificas pelo editor e as alterações se tornam visíveis imediatamente. Isso é muito mais fácil do que ter que rodar seus jogo toda vez que fizer alterações.

Vamos criar primeiro o efeito de explosão. Crie um novo arquivo em seu projeto e escolha o template iOS > Resource > SpriteKit Particle File

Particle File TemplateParticle File TemplateParticle File Template

No menu que aparecer, selecione Fire no Partcile template. Chame o arquivo de Explosion ou algo familiar.

Fire Particle TemplateFire Particle TemplateFire Particle Template

Após o Xcode criar o arquivo, você verá que há dois novos arquivos no projeto, Explosion.sks e spark.png.

Two Files Are AddedTwo Files Are AddedTwo Files Are Added

O Explosions.sks contém o sistema de partícula e é com este arquivo que vamos trabalhar. O segundo arquivo, spark.png, é uma imagem simples usada pelo template da partícula Fire para criar seu efeito visual. Se você abrir o Exposion.sks, você pode ver a animação do fogo.

Fire Particle SystemFire Particle SystemFire Particle System

As alterações mais importantes que precisamos fazer neste sistema de partícula é ter partículas se deslocando para fora do emissor em todas as direções e não gerar continuamente novas partículas.

Para a primeira alteração, abra o Attributes Inspector e na seção Particles altere o Angle Range para 360°.

Changing Angle RangeChanging Angle RangeChanging Angle Range

Imediatamente, você pode ver que agora as partículas se movem para fora em um circulo.

Circular FireCircular FireCircular Fire

Para evitar que o sistema de partículas crie continuamente novas partículas, podemos especificar um valor Maximum. Esse valor informa ao sistema de partícula quantas partículas no total serão criadas. O valor padrão 0, significa que não há um limite, o que faz com que novas partículas seja criadas continuamente. 

Além de especificar um valor máximo, também iremos alterar algumas outras propriedades para criar um efeito de explosão melhor. Na seção Particles do Attributes Inspector, altere os seguintes valores:

Explosion Custom PropertiesExplosion Custom PropertiesExplosion Custom Properties

Para o Birthrate atribuímos um valor maior que a propriedade Maximum, pois ela determina quantas partículas são criadas por segundo. Queremos que a explosão seja bem rápida. Então, ao invés de ter 1000 partículas aparecendo ao longo de um segundo, que é o que aconteceria com um Birthrate de 1000, especificamos um Birthrate de 5.000. Isso significa que todas as partículas serão criadas em apenas 0,2 segundos.

Atribuindo 3 para Lifetime > Start as partículas ficaram vivas por 3 segundos. A propriedades Lifetime Range pode ser usada para adicionar variações no tempo de vida nas partículas.

Por último, atribuímos 200 para Speed > Start, fazendo com que as partículas voem muito rapidamente a partir do emissor como aconteceria numa explosão real.

Após fazer essas alterações, você pode ver que o sistema de partículas ficará um pouco diferente e mais parecido com uma explosão real.

Explosion Particle SystemExplosion Particle SystemExplosion Particle System

Observe que, apesar da animação estar em um looping no editor do Xcode, o sistema de partícula só será executado uma vez quando adicionado à sua cena.

Com a partícula de explosão completa, é hora de seguir para o sistema de partícula da fumaça. Crie um novo arquivo, Smoke, usando o mesmo template que usamos para a explosão. A única diferença é o Particle template, que atribuiremos Smoke.

Smoke Particle TemplateSmoke Particle TemplateSmoke Particle Template

A única alteração que precisamos fazer para este sistema de partícula é ter a fumaça se movendo em forma de um círculo ao invés de apenas em linha reta. Faça assim, altere a propriedade Angle > Range para 360° como fizemos no sistema de partícula da explosão. Após feito isso, o sistema de partícula da fumaça ficará assim:

Smoke Particle SystemSmoke Particle SystemSmoke Particle System

Com ambos os sistemas de partículas prontos, podemos adiciona-los a nossa cena. Para fazer isso, carregaremos cada um dos arquivos que criamos como objetos SKEmitterNode e então adiciona-los a cena como um nó normal. Abra o MainScene.swift e substitua a implementação do didBeginContact(_:) conforme abaixo:

1
func didBeginContact(contact: SKPhysicsContact) {
2
    if contact.bodyA.node == player || contact.bodyB.node == player {
3
        if let explosionPath = NSBundle.mainBundle().pathForResource("Explosion", ofType: "sks"),
4
            let smokePath = NSBundle.mainBundle().pathForResource("Smoke", ofType: "sks"),
5
            let explosion = NSKeyedUnarchiver.unarchiveObjectWithFile(explosionPath) as? SKEmitterNode,
6
            let smoke = NSKeyedUnarchiver.unarchiveObjectWithFile(smokePath) as? SKEmitterNode {
7
            
8
            player.removeAllActions()
9
            camera?.removeAllActions()
10
            player.hidden = true
11
            player.removeFromParent()
12
            
13
            explosion.position = player.position
14
            smoke.position = player.position
15
            
16
            addChild(smoke)
17
            addChild(explosion)
18
        }
19
    }
20
}

Da mesma forma que a implementação anterior do didBeginContact(_:), vamos executar a mesma verificação após ver se os nós se envolveram em colisão com o carro. Então usamos o optional binding para pegar o caminho dos arquivos dos sistemas de partícula da explosão e da fumaça. Usaremos esses caminhos para instanciar os objetos SKEmitterNode.

Em seguida, removemos todas as ações, dos nós da câmera e do jogador, e tornamos o nó do jogador invisível para removê-lo da cena. Removemos o carro para evitar mais colisões que podem gerar mais explosões.

Então atribuímos a posição do carro aos nós emissores para então adicioná-los a cena. Como resultado, o Spritekit imediatamente começa a executar os sistemas de partículas.

Compile e rode seu jogo. Você pode ver o sistema de partícula explosão assim que o carro acerta um obstáculo. Que é seguido pela fumaça uma vez que o fogo se apaga.

Particles in SceneParticles in SceneParticles in Scene

2. Filtros de cenas e nós de efeito

No SpriteKit, há um tipo especial de nó (representado pela classe SKEffectNode) que pode usar um objeto de filtro Core Image (representado pela classe CIFilter) para processar seus nós filhos com uma variedade de efeitos. A classe SKScene é uma subclasse da SKEffectNode, o que significa que você pode então aplicar um filtro a cena toda.

Infelizmente, no momento da escrita deste tutorial, existem algumas questões relacionadas com esses nós de filtros e efeitos no iOS 9. Atualmente, quando um efeito está habilitado para um nó de efeito, todos os seus filhos ficam escondidos, o que resulta em o efeito de não ser visível.

Mesmo não podendo implementar isso em nosso jogo e ver o que acontece, ainda podemos executar o código a ser usado para criar um efeito. Neste caso, o método a seguir é um exemplo de adição e gradualmente desvanecendo-se um efeito de desfoque para toda a cena.

1
func addBlurFilter() {
2
    let blurFilter = CIFilter(name: "CIGaussianBlur")
3
    blurFilter?.setDefaults()
4
    blurFilter?.setValue(0.0, forKey: "inputRadius")
5
    filter = blurFilter
6
    shouldEnableEffects = true
7
    
8
    runAction(SKAction.customActionWithDuration(1.0, actionBlock: { (node: SKNode, elapsedTime: CGFloat) in
9
        let currentRadius = elapsedTime * 10.0
10
        blurFilter?.setValue(currentRadius, forKey: "inputRadius")
11
    }))
12
}

Criamos um objeto CIFilter de um tipo particular. Se você quer dar uma olhada em outros filtros disponíveis para você, verifique a Referência do Filtro Core Image. Garantimos este filtro com um valor de entrada padrão e então manualmente definimos 0.0 para o inputRadius, o que significa que não há um valor inicial de blur. 

Então atribuímos o filtro para a propriedade filter da cena atual e definimos o shouldEnableEffects com true para habilitá-lo. Por ultimo, rodamos uma SKAction que gradualmente aumenta o raio de entrada do filtro para 10.

Esperançosamente, em um lançamento futuro do iOS, esse erro no nó de efeito será corrigido, pois ele fornece uma forma de adicionar alguns efeitos únicos e interessantes para sua cena.

3. Nós de luz

O SpriteKit também inclui um excelente sistema de luz que pode ser usado para tornar a cena mais realista. As luzes são muito simples de implementar e são criadas através do uso da classe SKLightNode. Um nó de luz define certas propriedades, tais como a cor da luz (incluindo a cor ambiente) e sua força sobre a distância.

Em nossa cena, vamos criar uma simples luz branca que será anexada ao carro. Esta luz irá iluminar os obstáculos na frente do carro, assim como produzirá sombra.

Vamos começar criando uma luz no método didMoveToView(_:) da sua classe MainScene.

1
override func didMoveToView(view: SKView) {
2
   
3
   ...
4
   
5
    let light = SKLightNode()
6
    light.lightColor = UIColor.whiteColor()
7
    light.falloff = 0.5
8
    
9
    player.addChild(light)
10
}

Com este código, criamos um novo objeto SKLightNode, alteramos sua propriedade lightColor para branco e diminuímos sua propriedade falloff do valor padrão 1 para 0.5.

Assim como quando configuramos a detecção de colisão da físicas no SpriteKit, você deve especificar quais luzes interagem com quais nós em sua cena através do uso de máscaras de bits. Quando o SpriteKit renderiza a luz na cena, ele usa um operador lógico AND no categoryBitMaks do nó de luz e o lightingBitMask e shadowCastBitMask de cada outro nó para determinar que nó específico pode aparecer. 

Para nosso jogo, queremos que o obstáculos interajam com a luz de modo que eles gerem sobra na cena. Ao fazê-lo, adicionamos as duas linhas a seguir no final do método spawnObstacle(_:) da classe MainScene:

1
func spawnObstacle(timer: NSTimer) {
2
    
3
    ...
4
    
5
    obstacle.lightingBitMask = 0xFFFFFFFF
6
    obstacle.shadowCastBitMask = 0xFFFFFFFF
7
}

Definindo uma máscara de bit com todos os bits habilitados, os obstáculos interagem com todas as luzes da cena.

Compile e rode seu app. Você verá que, quando seu carro se move através da cena, cada obstáculos tem uma sombra dinâmica, que está sendo projetada a partir do centro do carro.

Shadows in SceneShadows in SceneShadows in Scene

Como você pode ver, no SpriteKit as luzes são muito simples de usar e podem adicionar ótimos efeitos a sua cena.

4. Nós de áudio

Finalmente, vamos dar uma olhada nos nós de áudio do SpriteKit. Nós de áudio são usados para adicionar efeitos de som à cena. Estes nós especiais são representados pela classe SKAudioNode. Como o SKAudioNode é uma subclasse SKNode, você pode adicionar e posicioná-lo em qualquer lugar na cena, como um nó normal.

Além de reproduzir áudio de uma forma regular e parecendo o mesmo, não importa o quanto sua cena é organizado (por exemplo, música de fundo), o SpriteKit permite que você utilize áudio posicional para criar um efeito verdadeiramente envolvente. Isso é feito especificando um nó listener para sua cena, que é da onde o som será "ouvido".

Nós de áudio são posicionais por padrão. Isso significa que, se você não quer usar esta funcionalidade em casos particulares, você pode definir uma propriedade especifíca do nó, positional, para false.

Embora não implementarmos isso em nosso jogo, o método de exemplo a seguir adiciona uma música de fundo na cena. No método, também adicionamos um som de explosão que começa a tocar quando nós pedirmos.

Perceba que importamos o framework AVFoundation na parte superior. Isso é necessário para acessar e trabalhar com a propriedade avAudioNode de um objeto SKAudioNode. Como você pode ver, os nós de áudio são muito simples de configurar e trabalhar no SpriteKit.

1
import AVFoundation
2
3
func addAudioNode() {
4
    
5
    listener = player
6
    
7
    let backgroundMusic = SKAudioNode(fileNamed: "backgroundMusic")
8
    backgroundMusic.positional = false
9
    
10
    let explosion = SKAudioNode(fileNamed: "explosion")
11
    explosion.autoplayLooped = false
12
    
13
    addChild(backgroundMusic)
14
    addChild(explosion)
15
    
16
    do {
17
        try explosion.avAudioNode?.engine?.start() // Called when you want to play sound

18
    } catch {
19
        // Do something with the error

20
    }
21
}

Conclusão

Você deve estar confortável agora em trabalhar com alguns dos mais avançados efeitos no SpriteKit, incluindo sistema de partículas, filtros, luzes e áudio. Estes efeitos combinados podem afetar muito a aparência do seus jogo e torná-lo mais imersivo.

No próximo e final tutorial desta série, cobriremos algumas das melhores práticas a se ter em mente quando trabalhar com SpriteKit. E também mostrarei como criar um atlas de textura e salvar/carregar cenas.

Como sempre, certifique de deixar seus comentários e feedback nos comentários abaixo.

Seja o primeiro a saber sobre novas traduções–siga @tutsplus_pt no Twitter!

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.