Unlimited WordPress themes, graphics, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. Xcode
Code

Uma introdução ao GameplayKit: Parte 2

by
Difficulty:IntermediateLength:LongLanguages:
This post is part of a series called An Introduction to GameplayKit.
An Introduction to GameplayKit: Part 1
An Introduction to GameplayKit: Part 3

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

Está é a segunda parte do Uma Introdução ao GameplayKit. Se você ainda não passou pela primeira parte, então eu recomendo a leitura deste primeiro tutorial antes de continuar com este.

Introdução

Neste tutorial, eu irei ensinar a você sobre mais duas funcionalidades do framework GameplayKit que você pode tirar vantagem:

  • agentes, metas e comportamentos
  • busca de caminho

Ao utilizar agentes, metas e comportamentos, nós iremos construir uma inteligência artificial (IA) básica no jogo que iniciamos na primeira parte desta serie. A IA permitira que nossos inimigos, ponto vermelho e ponto amarelo, se direcionem e se movam em direção ao nosso jogador, ponto azul. Nós também iremos implementar uma busca de caminho para ajudar esta IA a navegar em torno dos obstáculos.

Para este tutorial, você pode usar sua copia do projeto completado na primeira parte desta série ou fazer o download de uma copia fresquinha do nosso código no GitHub.

1. Agentes, metas e comportamentos

No Gameplaykit, agentes, metas e comportamentos são usados em combinação uns com os outros para definir como os diferentes objetos se movem em relação uns aos outros em todo seu cenário. Para um único objeto (ou SKShapeNode em nosso jogo), você começa criando um agente, representado pela classe GKAgent. Porém, para jogos 2D, como o nosso, nós precisamos usar a classe GKAgent2D.

A classe GKAgent é uma subclasse da GKComponent. Isso significa que seu jogo precisa estar usando uma estrutura baseada em entidade-componente, como mostrei a você no primeiro tutorial desta série.

Agentes constituem uma posição, tamanho e velocidade do objeto. Você também pode adicionar um comportamento, representado pela classe GKBehaviour, para este agente. Por ultimo, você cria um conjunto de metas, representados pela classe GKGoal, e adiciona elas ao objeto comportamento. Metas podem ser usadas para criar vários elementos diferentes de gameplay, por exemplo:

  • movimentar em direção a um agente
  • movimentar para longe de um agente
  • agrupar em conjunto com outros agentes
  • vagar em uma posição específica

Seu objeto comportamento, monitora e calcula todas as metas que você adicionar a ele e então retransmite esse dado de volto ao agente. Vamos ver como isso funciona na prática.

Abra o seu projeto no Xcode e navegue para o arquivo PlayerNode.Swift. Primeiro precisamos certificar que a classe PlayerNode está em conformidade com o protocolo GKAgenteDelegate.

Em seguida, adicione o bloco de código abaixo à classe PlayerNode.

Nós começamos adicionando uma propriedade à classe PlayerNode de modo que nós sempre temos uma referência ao objeto agente do jogador atual. Em seguida, implementamos os dois métodos do protocolo GKAgentDelegate. Através da implementação destes métodos, nós garantimos que o ponto do jogador mostrado na tela sempre espelhará as alterações que o GameplayKit fizer.

O método agentWillUpdate(_:) é chamado um pouco antes do GameplayKit verificar através dos comportamentos e metas deste agente para determinar para onde ele deve ser mover. Da mesmo forma, o método agentDidUpdate(_:) é chamado logo após o GameplayKit ter completado esse processo.

Nossa implementação desses dois métodos garante que o nó que vemos na tela reflete as alterações feitas pelo GameplayKit e que o GameplayKit usa a ultima posição do nó quando for executar seus cálculos.

Em seguida, abra o arquivo ContactNode.swift e substitua o seu conteúdo com a implementação abaixo:

Implementando o protocolo GKAgentDelegate na classe ContactNode, permitimos que todos os outros pontos do nosso jogo vão estar em dia com o GameplayKit, assim como nosso ponto do jogador.

Agora é hora de definir os comportamentos e metas. Para fazer funcionar, nós precisamos tomar cuidado com três coisas:

  • Adicionar o agente do nó do jogador a esta entidade e definir seu delegate.
  • Configurar os agentes, comportamentos e metas para todos os nossos pontos inimigos.
  • Atualizar todos esses agentes em tempo de execução.

Primeiramente, abra o arquivo GameScene.swift e no final do método didMoveToView(_:), adicione as duas linhas de código abaixo:

Com estas duas linhas de código, nós adicionamos o agente como um componente e definimos para o delegate do agente ser o próprio nó.

Em seguida, substitua a implementação do método initialSpawn com a implementação abaixo:

O código mais importante que nós adicionamos está localizado na instrução if que segue a instrução switch. Vamos percorrer este código linha por linha:

  • Primeiro adicionamos o agente à entidade como um componente e configuramos seu delegate.
  • Em seguida, nós atribuímos a posição do agente e adicionamos o agente ao array de armazenamento, agents. Vamos adicionar esta propriedade à classe GameScene em um momento.
  • Nós então criamos um objeto GKBehavior com um único GKGoal para direcionar ao agente do jogador corrente. O parâmetro weight(peso) neste inicializador é usado para determinar quais metas devem ter precedência sobre outras. Por exemplo, imagine que você tenha uma meta para se direcionar a um agente em particular e uma meta para se afastar de outro agente, mas você quer que a meta de direcionamento tenha preferência. Neste caso, você pode dar à meta de direcionamento um peso de 1 e à meta de se afastar um peso de 0.5. Este comportamento será então atribuído ao agente do nó inimigo.
  • Por ultimo, nós configuramos as propriedades mass, maxSpeed e maxAcceleration do agente. Isto afeta o quão rápido os objetos podem se mover e virar. Sinta-se livre para brincar com esses valores e ver como isso afeta o movimento dos pontos inimigos.

Em seguida, adicione as duas propriedades a seguir à classe GameScene:

O array agents será usado para manter uma referência dos agentes inimigo no cenário. A propriedade lastUpdateTime será usada para calcular o tempo que passou desde a ultima atualização do cenário.

Por último, substitua a implementação do método update(_:) da classe GameScene com a seguinte implementação:

No método update(_:), nós caculamos o tempo desde a ultima atualização do cenário e então atualizamos os agentes com esse valor.

Compile e rode seu app, e comece a se mover pelo cenário. Você notará que os pontos inimigos lentamente começaram a se mover atrás de você.

Targeting enemies

Como você pode ver, apesar dos pontos inimigos terem o jogador como alvo, eles não caminham em torno das barras brancas, ao invés disso, eles tentam se mover através delas. Vamos deixar os inimigos um pouco mais espertos com a busca de caminho.

2. Busca de Caminho

Com o framework Gameplaykit, você pode adicionar uma complexa lógica de busca de caminho em seu jogo combinando corpos físicos com classes e métodos do GameplayKit. Para o nosso jogo, nós iremos configurar para que os pontos inimigos se direcionarem ao ponto de jogador e ao mesmo tempo caminhem em torno dos obstáculos.

A busca de caminho no GameplayKit começa com a criação de um grafo do seu cenário. Este grafo é uma coleção de localizações individuais, também conhecidas como nós, e conexões entre estas localizações. Estas conexões definem como um objeto em particular pode se mover para outra localização. Um grafo pode modelar os caminhos disponíveis em seu cenário de três formas:

  • Um espaço contínuo contendo obstáculos: Este modelo de grafo permite caminhos suaves ao redor de obstáculos de um local para outro. Para este modelo, a classe GKObstacleGraph é usada para o grafo, a classe GKPolygonObstacle para os obstáculos e a classe GKGraphNode2D para os nós (localizações).
  • Uma simples grade 2D: Neste caso, localização validas podem ser apenas aquelas com coordenadas inteiras. Este modelo de grafo é útil quando seu cenário tem um layout de grade distinta e você não precisa de caminhos suaves. Ao usar este modelo, objeto podem se mover apenas na horizontal ou vertical em uma unica direção em qualquer momento. Para este modelo, a classe GKGridGraph é usada para o grafo e a classe GKGridGraphNode para os nós.
  • Uma coleção de localizações e as conexões entre elas: Este é o modelo gráfico mais genérico e é recomendado para casos onde objetos se movem entre espaços distintos, mas a sua localização específica dentro desse espaço não é essencial para o gameplay. Para este modelo, a classe GKGraph é usada para o grafo e a classe GKGraphNode para os nós.

Como queremos que o ponto azul do jogador em nosso jogo navegue em torno das barras brancas, nós iremos usar a classe GKObstacleGraph para criar um grafo do nosso cenário. Para começar, substitua a propriedade spawnPoints da classe GameScene com o seguinte:

O array spawnPoints contém alguns locais de spawn alterados para os fins deste tutorial. Isso ocorre porque atualmente o GameplayKit só pode calcular caminhos entre os objetos que estão relativamente próximos uns dos outros.

Devido à grande distância padrão entre os pontos neste jogo, alguns novos pontos de spawn deve ser adicionado para ilustrar a busca de caminho. Perceba que nós também declaramos uma propriedade graph do tipo GKObstacleGraph para manter uma referência do grafo que iremos criar.

Em seguida, adicione as duas linhas de código a seguir no inicio do método didMoveToView(_:).

Na primeira linha, nós criamos um array de obstáculos dos corpos físicos no cenário. Nós então criamos o objeto grafo usando estes obstáculos. O parâmetro bufferRadius neste inicializador pode ser usado para forçar os objetos há não entrarem a uma certa distância destes obstáculos. Estas linhas precisam ser adicionadas no inicio do método didMoveToView(_:), por que o grafo que criamos será necessário na hora em que o método initialSpawn for chamado.

Por último, substitua o método initialSpawn com a implementação abaixo:

Nós iniciamos o método criando um objeto GKGraphNode2D com as coordenadas de onde o jogador irá aparecer. Em seguida, nós conectamos ela ao grafo de modo que ele possa ser usado quando buscarmos os caminhos.

A maior parte do método initialSpawn permanece inalterado. Eu adicionei alguns comentários para mostrar á você onde a parte do código da busca de caminho está localizada na primeira instrução if. Vamos passar por este bloco passo a passo:

  • Nós criamos outra instância GKGraphNode2D e conectamos ela ao grafo.
  • Nós criamos uma série de nós que compõem um caminho, chamando o método findPathFromNode(_:toNode:) em nosso grafo.
  • Se a série de nós caminho for criada com sucesso, então nós criamos um caminho a partir deles. O parâmetro radius trabalho de forma similar ao parâmetro bufferRadius de antes e define quanto um objeto pode se mover para fora do caminho criado.
  • Nós criamos dois objetos GKGoal, um para seguir o caminho e outra para ficar no caminho. O parâmetro maxPredictionTime permite à meta calcular o melhor que puder antes do tempo se nada vai interromper o objeto a seguir/ficar nesse caminho particular.
  • Por último, nós criamos um novo comportamento com estas duas metas e atribuímos ele ao agente.

Você irá notar que nós removemos os nós que criamos a partir do grafo uma vez que terminamos com eles. Esta é uma boa prática a seguir, pois garante que os nós que você criou não interfiram mais tarde com qualquer outros cálculos de busca de caminho.

Compile e execute seu app uma ultima vez e você verá dois pontos aparecendo muito perto de você e começando a se mover atrás de você. Você pode ter que executar o jogo várias vezes se ambos aparecerem como pontos verdes.

Pathfinding enemies

Importante!

Neste tutorial, nós usamos a funcionalidade de busca de caminho do GameplayKit para permitir que os pontos inimigos se direcionem em sentido ao ponto do jogador em torno dos obstáculos. Note que se trata apenas de um exemplo prático de busca de caminho.

Para um jogo de produção real, seria melhor implementar essa funcionalidade combinando a meta de direcionamento usado mais cedo neste tutorial com a meta de evitar os obstáculo criados com o método de conveniência init(toAvoidObstacles:maxPredictionTime:), qual você pode ler mais na Referência da classe GKGoal.

Conclusão

Neste tutorial, eu mostrei à você como você pode utilizar os agentes, metas e comportamentos em seu jogo que tiver uma estrutura entidade-componente. Apesar de criarmos apenas três metas neste tutorial, há muito mais formas disponíveis, que você pode ler na Referência da classe GKGoal.

Eu também mostrei como implementar uma busca de caminho avançada em seu jogo criando um grafo, um conjunto de obstáculos e metas para seguir estes caminhos.

Como você pode ver, existe uma grande quantidade de funcionalidades disponíveis para você através do framework GameplayKit. Na terceira e final parte desta série, eu irei ensinar sobre geradores de valor aleátorio do GameplayKit e como criar seu próprio sistema de regras para introduzir uma lógica fuzzy em seu jogo.

Como sempre, por favor deixe seu comentário e feeedback abaixo.

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

Advertisement
Advertisement
Advertisement
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.