Buscar

Curso Jogos mobile com Unity Diversão com a Game Engine

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 100 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 6, do total de 100 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 9, do total de 100 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Prévia do material em texto

Configurando o projeto e 
movimentando o inimigo 
Porque usar um game engine? 
A maior dificuldade enfrentada quando queremos começar a desenvolver jogos é 
justamente descobrir por onde começar. Existem muitas maneiras diferentes de começar 
e a quantidade de informação é tão grande que acabamos nos perdendo em meio a tantas 
possibilidades. 
Ainda assim, quando vencemos esse primeiro obstáculo, escolhemos uma linguagem de 
programação e iniciamos o desenvolvimento, logo percebemos que precisamos escrever 
muito código para realizar tarefas essenciais como desenhar imagens na tela, emitir 
sons, capturar entrada através de gamepads, teclado ou mouse, entre outras. Com isso, 
acabamos perdendo muito tempo trabalhando para preparar toda essa base antes mesmo 
de começar a desenvolver a ideia do nosso jogo. É justamente nessa fase que a maioria 
dos aspirantes a desenvolvedores de jogos acaba desistindo. 
Uma boa notícia é que muitos desenvolvedores já passaram por isso antes e decidiram 
resolver esse problema para facilitar o desenvolvimento de seus próximos jogos ou para 
ajudar outros desenvolvedores. Como essas tarefas são bastante comuns e como 
praticamente todos os jogos fazem uso delas, faz sentido escrever o código para todas 
elas uma única vez e disponibilizar esse código em forma de bibliotecas. Assim, 
utilizando essas bibliotecas podemos começar a codificar diretamente as regras do nosso 
jogo sem nos preocuparmos com as tarefas mais básicas. 
Quando reunimos esse conjunto de bibliotecas com o objetivo de fornecer 
um framework para a execução de jogos, estamos criando o que chamamos de um game 
engine. Um game engine (motor de jogos) é capaz de executar vários tipos de jogos 
diferentes assim como um motor pode ser usado para mover os mais diversos objetos 
como carros, esteiras, hélices e turbinas. Geralmente, um game engine possui um 
conjunto de subsistemas que são responsáveis por tipos específicos de tarefas. Os 
principais subsistemas de um game engine são apresentados abaixo: 
 Renderização 2D/3D - responsável por todas as tarefas relacionadas ao desenho 
de objetos, efeitos especiais, vídeos na tela, entre outros. 
 Áudio - responsável pela emissão de efeitos sonoros a partir de arquivos às vezes 
utilizando recursos mais avançados como sons posicionais 3D. 
 Física - responsável pela simulação da movimentação dos objetos de um jogo com 
base nas leis da física como conhecemos. 
 Colisões - responsável pela detecção de colisão entre os objetos de um jogo. 
 Scripts - responsável pela interpretação de scripts contendo regras ou 
comportamento de objetos do jogo e que facilitam a customização por 
desenvolvedores, designers e artistas. 
 Entrada - responsável pela captura dos comandos de dispositivos de entrada como 
teclado, mouse, gamepads e sensores diversos. 
Hoje existem muitos game engines disponíveis para quem deseja desenvolver um jogo. 
Dentre os mais conhecidos podemos citar o Unreal Engine famoso pelas 
franquias Unreal Tournament e Bioshock; Crytek Engine conhecido pela série de 
jogos Crysis; Source Engine responsável por jogos de sucesso como Half-
life e Portal; e o Unity mais famoso por jogos como Hearthstone e Ori and the Blind 
Forest. 
Antigamente o uso desses game engines estava restrito a grandes produtoras devido ao 
custo elevado de aquisição das licenças mas recentemente tem havido uma mudança na 
estratégia de comercialização desses produtos. O Unreal Engine 4, o Source Engine 
2 e o Unity 5 agora podem ser utilizados de graça sem a necessidade de se adquirir uma 
licença. Você só precisará adquirir uma licença ou pagar royalties depois de ter 
produzido e comercializado seu jogo. 
O Unity 
Apesar de termos várias opções de engines para desenvolvimento de jogos, o Unity vem 
ganhando bastante destaque nesse mercado bastante concorrido. Isso acontece porque o 
Unity foi criado desde o início tendo em mente a sua utilização tanto por 
desenvolvedores quanto por artistas e designers, que geralmente produzem recursos e 
documentação mas não são incluídos no processo de desenvolvimento de um jogo. 
Isso acabou abrindo as portas para que eles pudessem contribuir mais ativamente 
durante o processo de desenvolvimento através de uma ferramenta integrada e 
expansível que permite que artistas possam realizar ajustes relativos ao visual de um 
jogo sem a necessidade de escrever uma linha de código sequer. O mesmo acontece 
com os designers que puderam auxiliar, por exemplo, no balanceamento dos jogos, na 
criação de novo conteúdo ou em ajustes simples das regras de jogo também sem 
precisar escrever código para isso. 
Outra característica que permitiu a entrada do Unity nesse mercado tão concorrido foi 
a Asset Store. A Asset Store é uma loja de recursos que podem ser adquiridos (pagos 
ou grátis) e utilizados na criação de jogos. Esses recursos variam desde modelos 3D, 
imagens e sons até scripts, ferramentas adicionais e efeitos visuais. Qualquer usuário do 
Unity pode compartilhar ou vender seus recursos na Asset Store criando uma fonte 
bastante rica de recursos para qualquer um que queira criar um jogo. 
Uma outra grande vantagem do Unity é a sua capacidade de publicar um mesmo jogo 
em mais de 20 plataformas diferentes incluindo as plataformas Android, iPhone, 
Playstation (3, 4, Vita), XBox (360, One), Nintendo (Wii U, 3DS), PC Desktop, PC 
Web, entre outras. 
Por todos esses motivos, escolhemos o Unity como a ferramenta mais adequada tanto 
para quem está começando no desenvolvimento de jogos quanto para quem já conhece 
um pouco do assunto e quer ganhar mais produtividade sem ter que reinventar a roda. 
Criando um novo projeto 
Antes de podermos criar um jogo no Unity precisamos baixar a última versão do engine. 
Para isso podemos visitar o site oficial do Unity: http://www.unity3d.com. Depois 
disso, basta visitar o link Get Unity e depois clicar no botão Free Download localizado 
ao final da coluna Personal Edition. Agora é só clicar no botão Download 
Installer para iniciar o download do instalador do Unity. 
Depois de baixado o instalador do engine, basta executar o arquivo e seguir os passos 
do wizard de instalação. Com isso, um ícone do Unity vai ser criado no seu Desktop. 
Agora para iniciar o Unity, basta dar um duplo clique nesse ícone e aguardar a 
inicialização. A primeira tela exibida pelo Unity será a apresentada na figura abaixo: 
 
Nesta tela o Unity mostra uma lista com os projetos mais recentes e também dois 
botões: Open Other prá abrir um projeto que não esteja na lista e New Project para 
criar um novo projeto. 
Para começarmos o desenvolvimento de um jogo no Unity precisamos criar um projeto 
então vamos utilizar o botão New Project. Depois de clicar nesse botão, o Unity 
mostrará a tela de criação de projetos mostrada abaixo: 
 
Nesta tela podemos dar um nome para o nosso projeto em Project Name e escolher em 
que pasta ficarão os seus arquivos em Location. Podemos também dizer se o nosso 
projeto será um jogo 2D ou 3D clicando nos textos de mesmo nome nessa janela. 
Depois de preenchidos os campos, podemos criar em Create Project para criar o 
projeto e abrir o editor do Unity pronto prá começar! 
O editor do Unity 
Sempre que abrirmos um projeto no Unity, a primeira tela que veremos será a janela do 
editor apresentada abaixo: 
 
É no editor que passaremos a maior parte do tempo durante a criação do nosso jogo. Por 
esse motivo é interessante configurar o layout do editor para que as ferramentas mais 
importantes fiquem sempre ao nosso alcance. 
O editor do Unity já possui algum padrões de layout de tela pré-configurados para o 
uso. Para acessá-los devemos clicar na caixa de opções de nome Layout logo acima da 
aba Inspector, localizada do lado direito da janela como ilustrado na figura abaixo: 
 
Apesar de já possuir algum padrões prontos, recomendamos começar com o padrão 2 
by 3 e alterar a posiçãode algumas abas para facilitar o trabalho dentro do editor até 
alcançar a configuração mostrada abaixo: 
 
Nesta configuração, temos do lado esquerdo as abas Scene e Game, que são 
visualizações do nosso jogo, e do lado direito as abas Hierarchy, Project e Inspector, 
que serão usadas para organização, criação e configuração dos objetos e recursos do 
jogo. 
Com isso estamos prontos para começar a criação do nosso jogo! 
As regras do jogo: Defesa de Torres 
Durante o curso construiremos um jogo do início ao fim começando pela criação do 
projeto e adicionando aos poucos novas funcionalidades até ter um jogo completo. 
O jogo que criaremos será um tower defense. Neste jogo o jogador deve construir torres 
em posições estratégicas para criar uma linha de defesa contra inimigos invasores. Caso 
um inimigo consiga cruzar a linha de defesa sem ser destruído, o jogador é penalizado 
com a perda de uma vida. Se as vidas do jogador acabarem então é fim de jogo. O 
objetivo final é sobreviver o maior tempo possível à invasão. 
Construindo o cenário do jogo com Game Objects 
O que são Game Objects? 
No Unity, cada objeto dentro de uma cena é chamado de Game Object, por exemplo: 
personagens, luz, câmera, partículas... Se todos esses diferentes objetos são Game 
Objects, como diferenciamos uma câmera de uma partícula? 
Por padrão, um Game Object não tem nenhum comportamento específico. Sua 
diferenciação é feita a partir do conjunto de componentes (components) que escolhemos 
para esse objeto. Então, uma câmera é um Game Object que possui um conjunto de 
componentes diferentes de uma partícula, que também é um Game Object! 
Como todo Game Object é um objeto dentro da nossa cena, como fazemos para 
posicioná-lo num ponto específico do nosso ambiente? 
Uma componente muito importante dos Game Objects é o Transform, que permite 
configurarmos vários atributos interessantes, como escala (scale), rotação (rotation) 
e posição (position). 
 
Então, para configurarmos a posição de qualquer Game Object na nossa cena, basta 
acessarmos o atributo Position do componente Transform! 
Terreno: nosso segundo Game Object 
Temos nosso inimigo criado, mas ele ainda está "flutuando" na nossa cena. Para 
melhorar isso, vamos criar o chão do nosso jogo! 
Como o chão é um objeto da nossa cena, criaremos outro Game Object: o Terrain. 
Ao clicarmos na aba Hierarchy -> Create -> 3D Object -> Terrain, veja que 
esse Game Object criado possui um outro componente além do Transform, 
chamado Terrain: 
 
Nesse componente podemos customizar as propriedades do nosso chão, como largura, 
profundidade, resolução, cores... Além disso podemos criar elevações e depressões no 
relevo desse terreno! 
Manipulando a Câmera 
Logo ao criarmos nosso projeto no Unity, a própria ferramenta já cria uma cena com 
dois Game Objects: uma câmera principal e uma luz padrão. Podemos alterar seus 
atributos! 
Podemos clicar na câmera principal (Main Camera) e, na aba Inspector, manipular os 
seus componentes, como oTransform e Camera. 
No componente Camera, podemos manipular o atributo Field of View que representa 
o ângulo de visão da nossa câmera. 
Para saber mais: Field of View 
O olho humano possui um ângulo de visão (field of view) de aproximadamente 180 
graus, porém num jogo em primeira-pessoa costumamos usar valores bem mais baixos 
que esse pois o cérebro humano acredita estar olhando para uma simples janela. 
É bastante comum encontrarmos jogos com field of view em torno de 70 graus, 
aumentando de acordo com a quantidade de monitores ligados até 120 graus. 
Movimentando o inimigo por um caminho 
Dando vida ao jogo 
Agora que já temos uma cena com alguns dos principais elementos do nosso jogo, 
vamos começar a adicionar algumas funcionalidades começando pelo movimentação do 
inimigo. 
Da forma como o jogo se encontra no momento, nosso inimigo poderia se movimentar 
em qualquer direção sem nenhum obstáculo em seu caminho. Além disso, dessa forma 
não ficaria claro para o jogador onde o inimigo está querendo chegar. 
Para melhorar isso, vamos começar adicionando detalhes ao nosso terreno para mostrar 
qual será o caminho a ser percorrido pelo inimigo. Para isso vamos precisar fazer 
modificações no objeto Chao que criamos anteriormente. 
Terrain e suas ferramentas 
O objeto Chao é um Terrain que permite a modelagem de terrenos de forma bem 
simples e intuitiva. Quando selecionamos um objeto do tipo Terrain, 
o Inspector exibe o componente Terrain que utilizaremos para desenhar o terreno do 
nosso jogo. Inicialmente, nesse componente temos apenas uma barra de ferramentas 
como na figura abaixo: 
 
A primeira ferramenta que vamos usar é a Raise / Lower Terrain correspondente ao 
primeiro botão da barra de ferramentas. Essa ferramenta serve para definir o relevo do 
nosso terreno permitindo a criação de elevações e depressões de forma bem fácil! 
Ao clicar nessa ferramenta, o componente irá exibir no Inspector as suas opções como 
ilustrado na figura: 
 
Na seção Brushes, podemos escolher o formato do pincel que usaremos para criar 
elevações ou depressões no terreno. Logo abaixo, temos a seção Settings onde 
podemos escolher o tamanho do pincel em Brush Size e a sua opacidade (força) 
em Opacity. 
Após configurar essas opções, podemos criar elevações no terreno clicando e arrastando 
o mouse sobre o terreno na abaScene. Para diminuir a elevação do terreno e criar 
depressões, basta clicar e arrastar sobre o terreno segurando a teclaSHIFT. 
Agora que já sabemos como usar a ferramenta, podemos criar um terreno irregular bem 
mais interessante que o anterior! Por exemplo, podemos modelar um terreno como o 
abaixo: 
 
Para delimitar o caminho, vamos utilizar mais uma ferramenta do componente Terrain. 
Novamente, com o Chaoselecionado, vamos agora utilizar a segunda ferramenta desse 
componente mostrada na figura abaixo: 
 
Essa ferramenta serve para criar regiões que possuam uma mesma altura escolhida por 
nós. Dessa forma, fica fácil definir áreas planas no terreno. 
Assim como na ferramenta anterior, temos uma seção Brush e uma 
seção Settings com as mesmas funcionalidades. A diferença está no funcionamento da 
ferramenta e na adição do atributo Height e do botão Flatten. Para utilizar a 
ferramenta basta clicar e arrastar sobre o terreno na aba Scene. Nesse caso, a ferramenta 
irá modificar a altura do terreno na região clicada para a altura definida no 
atributo Height. Além disso, também podemos resetar a altura do terreno inteiro de 
uma só vez definindo a altura em Height e clicando no botão Flatten. 
Então agora podemos delimitar o caminho a ser percorrido definindo Height como 0 e 
desenhando um caminho na abaScene começando no lado esquerdo do terreno e 
terminando no lado direito. Por exemplo, podemos desenhar um caminho como o 
exibido na figura abaixo: 
 
Como agora definimos um contraste entre o caminho e o restante do cenário, fica fácil 
para o jogador perceber por onde o inimigo irá passar e onde ele pretende chegar. 
Delimitando a área de movimento com a NavMesh 
Com o caminho definido, precisamos agora fazer com o que inimigo consiga se mover 
por este caminho sem se desviar. Mas como vamos fazer nosso inimigo saber por onde 
ele pode andar? Para isso utilizaremos o que chamamos no Unity deNavMesh. 
Uma NavMesh (abreviação de navigation mesh) é um modelo poligonal que serve para 
indicar por onde os objetos podem se mover. Além disso, a NavMesh permite que os 
objetos encontrem facilmente o menor caminho para se chegar em um determinado 
ponto. 
Para criar uma NavMesh, vamos abrir a janela Navigation indo no menu Window -> 
Navigation. Antes de gerar aNavMesh precisamos configurar alguns parâmetros para 
indicar onde nosso inimigo pode caminhar. Na janelaNavigation, vamos clicar no 
botão Bake para ter acesso às opções abaixo: 
 
Esses parâmetros são utilizados para dizer ao Unity como a NavMesh deve sergerada. 
Os atributos Agent Radius eAgent Size servem para indicar qual será o tamanho dos 
objetos que se moverão pela NavMesh. O atributo Max Slopeindica qual a inclinação 
máxima pela qual um objeto pode se mover e o atributo Step Height qual a altura 
máxima aceitável para um degrau que o objeto pode subir ou descer. 
Com os parâmetros configurados, basta clicar no botão Bake na parte inferior da 
janela Navigation. O Unity irá gerar aNavMesh e apresentá-la na aba Scene como na 
figura abaixo: 
 
A NavMesh, apresentada como uma malha na cor azul sobre o terreno, representa a área 
que poderá ser acessada por um objeto que se mova sobre ela. Caso 
a NavMesh apresente alguma região muito estreita ou não forme uma única área 
contínua, os objetos não conseguirão se locomover corretamente. Nesses casos, 
precisaremos gerar novamente aNavMesh com novos parâmetros ou depois de fazer 
ajustes no terreno. 
Transformando o inimigo em um NavMeshAgent 
Agora que criamos a NavMesh, como fazemos para dizer para o nosso inimigo que ele 
deve se mover respeitando os limites dela? 
A forma de fazer isso no Unity é indicando que o inimigo é um objeto que sabe interagir 
com uma NavMesh. Para isso, basta adicionar um componente 
chamado NavMeshAgent ao nosso objeto Inimigo. Na ferramenta, selecionamos o 
objeto Inimigo e no Inspector clicamos em Add Component -> Navigation -> 
Nav Mesh Agent. Agora noInspector, temos várias novas opções relacionadas ao 
movimento desse objeto na NavMesh como apresentado na figura abaixo: 
 
Para adequar o nosso inimigo ao NavMesh, precisamos indicar o tamanho do nosso 
objeto alterando seu raio em Radiuse sua altura Height em Agent Size. Além disso, 
alteramos também a velocidade do objeto Speed = 1 em Steering. Para finalizar, 
alteramos o atributo Quality = None em Obstacle Avoidance para que o inimigo 
possa se locomover sem se preocupar em colidir com outros objetos ou com o cenário. 
Fazendo o inimigo se mover com script 
Tendo criado a NavMesh e transformado o inimigo em um NavMeshAgent, como fazer 
para dizer ao inimigo para onde ele deve ir? 
Para fazer isso vamos ter que criar um novo comportamento para o nosso inimigo 
dizendo que ele deve se locomover para o fim do caminho assim que o jogo começar. 
Comportamentos de objetos no Unity são definidos através de scripts escritos em C#. 
Todo script depois de criado poderá ser usado como um componente em qualquer 
objeto do Unity. Para criar um novo script, podemos selecionar o objeto Inimigo e 
depois clicar em Inspector -> Add Component -> New Script. Depois basta 
preencher o campoName = Inimigo e clicar em Create and Add. 
Para editar o script, podemos dar um duplo clique em Project -> Inimigo. Neste 
momento, o Unity abrirá uma ferramenta externa para edição de scripts: 
o MonoDevelop. 
No MonoDevelop, o script Inimigo será exibido contendo o seguinte código: 
using UnityEngine; 
using System.Collections; 
 
public class Inimigo : MonoBehaviour 
{ 
 
 // Use this for initialization 
 void Start () 
 { 
 
 } 
 
 // Update is called once per frame 
 void Update () 
 { 
 
 } 
} 
Note que o script Inimigo herda da classe MonoBehaviour para indicar que o nosso 
script é um comportamento do Unity e como tal poderá ser utilizado como um 
componente no editor. Além disso, temos os métodos Start e Update. Por enquanto, 
utilizaremos apenas o Start que é o método invocado automaticamente pelo Unity no 
momento que o objeto é criado. 
Vamos aproveitar esse método para ordenar que o inimigo se mova até o fim do 
caminho utilizando a NavMesh como guia. Mas quem é o componente responsável por 
fazer com que nosso objeto interaja com a NavMesh? O NavMeshAgent! Então vamos ter 
que pedir para o NavMeshAgent realizar essa tarefa. 
Para manipularmos algum componente de um objeto no script, precisamos ter uma 
referência para ele. Conseguimos essa referência utilizando o 
método GetComponent como no código abaixo: 
NavMeshAgent navMeshAgent = GetComponent<NavMeshAgent>(); 
Agora que temos uma referência para o componente NavMeshAgent do nosso Inimigo, 
basta invocar o métodoSetDestination neste componente como no código abaixo: 
public class Inimigo : MonoBehaviour 
{ 
 void Start () 
 { 
 NavMeshAgent agente = GetComponent<NavMeshAgent>(); 
 agente.SetDestination (/*como saberemos a coordenada do fim do 
caminho?*/); 
 } 
} 
Mas ainda temos um problema: o método SetDestination recebe uma posição como 
parâmetro indicando prá onde o objeto deve se mover. Como vamos indicar a posição 
do final do caminho? 
Para não termos que especificar as coordenadas do final do caminho na mão, podemos 
criar um game object vazio com o nome FimDoCaminho em nossa cena e posicioná-lo 
no fim do nosso caminho. Assim podemos utilizar a posição desse objeto como 
referência de posição para o método SetDestination! 
Ainda assim, precisamos de uma forma de obter uma referência para esse objeto. Nesse 
caso, podemos utilizar o métodoGameObject.Find passando o nome de um objeto da 
cena como parâmetro para receber uma referência para esse objeto: 
GameObject fimDoCaminho = GameObject.Find ("FimDoCaminho"); 
Finalmente, tendo a referência para o objeto, podemos acessar o 
atributo transform.position desse objeto para conseguir sua posição. Juntando tudo 
isso, teremos o seguinte código no script Inimigo: 
public class Inimigo : MonoBehaviour 
{ 
 void Start () 
 { 
 NavMeshAgent agente = GetComponent<NavMeshAgent>(); 
 GameObject fimDoCaminho = GameObject.Find ("FimDoCaminho"); 
 Vector3 posicaoDoFimDoCaminho = 
fimDoCaminho.transform.position; 
 agente.SetDestination (posicaoDoFimDoCaminho); 
 } 
} 
Com o script finalizado, basta rodar o jogo agora para verificar que tudo está 
funcionando. Vamos então clicar no botão de Play localizado na barra de ferramentas 
superior do editor como indicado na imagem abaixo: 
 
Quando estamos executando o jogo, o editor do Unity entra no play mode. Durante o 
teste do jogo, podemos manipular nossa cena criando ou removendo objetos e também 
alterando seus parâmetros através do Inspector. Isso é ótimo para fazer um ajuste fino 
de detalhes que são melhores vistos enquanto o jogo está rodando. Mas fique alerta! 
Todas alterações realizadas no play mode são desfeitas quando encerramos a sessão de 
teste clicando novamente no botãoPlay. 
Luz ambiente do nosso jogo 
Além da câmera padrão, temos uma directional light criada por padrão pronta para 
manipularmos no nosso jogo! Dessa vez, podemos alterar o componente Light. 
 
Além da sua cor (Color), podemos configurar a intensidade (Intensity) da luz, sua 
sombra (Shadow type) e até mesmo sua reflexão nos objetos (Bounce Intensity). 
Veja que temos quatro tipos de luz: 
 Point: esse tipo de luz tem o máximo de iluminação no seu centro e vai 
escurecendo quanto mais longe estamos desse centro. É usado quando queremos 
simular um poste de luz, ou uma lâmpada, ou até mesmo explosões. 
 Spot: é bem parecido com o point light, mas fica confinada a um cone de direção. 
Faróis de carros, luzes de palco são bons exemplos desse tipo de luz. 
 Directional: neste tipo de luz não temos uma origem definida, nos importa 
somente a sua direção. Podemos simular a luz do sol ou da lua com ela. 
 Area: em vez de criarmos vários point lights, podemos criar uma iluminação numa 
área. Neste caso os raios de luz serão disparados em várias direções dentro desta 
área. Dessa forma podemos simular uma iluminação dentro de casa de forma mais 
realista. 
Como o cálculo de iluminação é algo bastante custoso para o processador, podemos 
determinar se queremos uma iluminação em tempo-real ou pré-calculada 
pela engine alterando a opção Baking. 
Porém, podemos fazer essa configuração para todas as luzes da nossa cena acessando 
um painel específico de iluminação chamado Lighting. 
 
Nestepainel, podemos desmarcar a opção Continuous Baking. 
 
Criando o projeto 
Primeiramente, temos que baixar o Unity do seu site oficial e instalá-lo. 
Agora, podemos criar o projeto que utilizaremos durante todo o curso: 
1. New Project. 
2. Digite TowerDefense no campo Project Name 
em Create Project. 
3. Com isso, a janela principal do e 
janela Unity Editor Update Check -a. 
Sugira uma correção 
Você não precisa submeter a resposta desse exercício. 
 
Criando o inimigo 
https://unity3d.com/get-unity/download?ref=personal
https://www.alura.com.br/course/jogos-mobile-com-unity/section/1/exercise/1
Para criar o inimigo, vamos dar um clique com o botão 
direito dentro de Hierarchy e, na sequência, Create -> 3D Object -> Cube. 
Após a criação do nosso cubo, vamos renomeá-lo para Inimigo na 
aba Inspector. 
 
Ainda na aba Inspector, além de alterar o nome do nosso Game Object, 
vamos modificar as dimensões do Inimigo e sua posição: 
1. Na aba Inspector em Transform -> Position, vamos 
colocar 0.1 no eixo Y. 
2. Agora, em Transform -> Scale, coloque 0.2 no X, Y e Z. 
Onde ficou posicionado o Inimigo? 
 
Construindo o terreno 
Vamos criar o terreno do nosso jogo! Basta clicarmos com o botão direito 
em Hierarchy e Create -> 3D Object -> Terrain. Vamos aproveitar e 
renomear esse terreno para Chao, na aba Inspector. 
Cuidado para não criar o Chao dentro do Inimigo. Neste momento, 
nossos game objects devem ficar no mesmo nível em vez de um dentro 
do outro. 
Agora, vamos selecionar o Chao, pois precisamos alterar algumas das 
suas propriedades: 
1. Em Inspector -> Transform -> Position vamos deixar X = -7, Y = 
0 e Z = -4. 
2. Na aba Inspector em Terrain, vamos selecionar o botão com uma 
engrenagem (o Terrain Settings). 
 
 No grupo Base Terrain, selecione Custom para Material. 
 
 Em Resolution, colocaremos Terrain Width = 14, Terrain Length = 
8, Terrain Height = 16 eHeightmap Resolution = 129. 
Com o Chao criado, vamos criar uma pasta no nosso projeto. 
1. É só clicar com o botão direito em Project -> Create -> Folder e 
renomear essa pasta para Assets. 
2. Agora, vamos arrastar o Project/New Terrain para a pasta Assets. 
Neste momento, quantos game objects temos no nosso jogo? 
 
Configurações da câmera 
Ao criarmos um jogo no Unity, uma câmera padrão já é criada para 
nosso uso. Vamos alterar alguns parâmetros para nosso jogo ficar legal. 
1. Em Hierarchy, selecione Main Camera. 
2. Na aba Inspector, vamos renomeá-la para Camera. 
3. Em Inspector -> Transform -> Position deixaremos X = 0, Y = 
7.5 e Z = -6.6. 
4. Em Inspector -> Transform -> Rotation colocaremos X = 55. 
Além de alterarmos o posicionamento e rotação da Camera, vamos 
configurar também o seu zoom. 
Com a Camera selecionada, vamos em Inspector -> Camera -> Field of 
View e colocaremos o valor 45 na barra deslizante. 
O que é field of view? 
 
Modelando o cenário 
Vamos começar modelando o terreno onde futuramente construiremos 
nossas defesas. 
Selecione o objeto Chao na aba Hierarchy. 
Na aba Inspector -> Terrain, selecione a ferramenta Raise / Lower 
Terrain: 
 
Agora, na aba Scene, modele as elevações do cenário clicando com 
o botão esquerdo do mouse para elevar o terreno no ponto clicado ou 
utilizando o comando SHIFT + botão esquerdo do mouse para baixar o 
terreno no ponto clicado. Cuidado para não gerar um terreno muito 
acidentado ou plano demais. Seu cenário deve ficar parecido com o da 
figura abaixo: 
 
Sugira uma correção 
Você não precisa submeter a resposta desse exercício. 
 
Construindo o caminho 
Agora que já temos o terreno modelado, vamos construir o caminho que 
será percorrido pelos inimigos. 
Na aba Inspector -> Terrain, selecione a ferramenta Paint height: 
 
Digite o valor 0 em Inspector -> Terrain -> Height. 
Na aba Scene, clique e arraste com o botão esquerdo do mouse sobre o 
terreno para desenhar o caminho. Seu caminho deve ficar parecido com 
a figura abaixo: 
https://www.alura.com.br/course/jogos-mobile-com-unity/section/1/exercise/5
 
Aproveite o espaço do terreno para desenhar seu caminho mas lembre-
se de que deve sobrar espaço suficiente para que o jogador construa as 
torres futuramente. Além disso, procure não fazer um caminho estreito 
demais, caso contrário os inimigos não conseguirão se mover com a 
velocidade necessária. 
Sugira uma correção 
Você não precisa submeter a resposta desse exercício. 
 
Criando o Navigation Mesh 
Para que os inimigos possam se mover apenas pelo caminho, 
precisamos gerar uma NavMesh que será um modelo auxiliar de 
navegação que será produzido a partir do nosso terreno. 
1. Vá em Menu -> Window -> Navigation para abrir a 
aba Navigation onde configuraremos a geração daNavMesh. 
2. Em Navigation -> Bake -> Baked Agent Size, vamos colocar Agent 
Radius = 0.15 e Max Slope = 0 e então clicar no botão Bake. 
3. Verifique se a NavMesh gerada e apresentada na 
aba Scene representa um caminho contínuo sem interrupções 
como o mostrado na figura abaixo. Caso isso não aconteça, 
selecione novamente o objeto Chao em Hierarchy e utilize as 
ferramentas de terreno para alargar o caminho nos locais 
necessários e repita o passo anterior. 
https://www.alura.com.br/course/jogos-mobile-com-unity/section/1/exercise/6
 
O que aconteceria se criássemos nosso navmesh com um Max 
Slope maior que zero? 
 
Alinhamento do inimigo no caminho 
Vamos preparar o nosso Inimigo para que ele consiga se mover pelo 
caminho. Para isso, vamos posicioná-lo no início do caminho e orientá-lo 
na direção do caminho. 
1. Selecione o objeto Inimigo na aba Hierarchy e posicione-o no início 
do caminho. Para isso utilize a ferramenta apresentada na figura 
abaixo. 
 
Para não corrermos o risco de alterarmos a posição Y do inimigo ao 
movê-lo, podemos movimentá-lo clicando e arrastando sobre as setas 
vermelha e azul. Desse modo, o movimento fica restrito ao eixo 
selecionado. 
1. Agora rotacione o Inimigo para que seu eixo Z aponte na direção 
do caminho. Para isso, selecione o Inimigo e no Inspector -> 
Transform clique e arraste sobre o eixo Y para rotacionar até que o 
eixo Z aponte para a direção correta. 
 
Movimentando o inimigo (parte 1) 
Precisamos agora fazer com que nosso Inimigo se mova. Primeiramente, 
vamos adicionar um novo comportamento a ele para que ele possa 
utilizar a NavMesh como referência para se locomover. 
1. Com o Inimigo selecionado, clique no botão Add Component e 
selecione Navigation -> Nav Mesh Agent. 
2. Em Inspector -> Nav Mesh Agent -> Agent Size, coloque Radius = 
0.1 e Height = 0.2. Esses parâmetros representam o raio e a altura 
do nosso Inimigo que serão considerados quando este estiver se 
locomovendo pela NavMesh. 
 
Movimentando o inimigo (parte 2) 
Agora sim, precisamos criar e associar um novo script ao 
nosso Inimigo que ficará responsável por pedir que oInimigo se 
movimente da posição atual até o final do caminho quando o nosso jogo 
for iniciado. 
Com o Inimigo selecionado, na aba Inspector, clique em Add Component, 
selecione New Script, preencha Name = Inimigo e clique em Create and 
Add. 
Veja que agora temos um script Inimigo e um objeto Inimigo, ficou mais 
difícil para nos localizarmos no nosso projeto. Vamos arrumar isso? 
1. Clique com o botão direito em Project -> Create -> Folder e 
renomeie a pasta para Script. 
2. Arraste nosso script Inimigo para a pasta Script. 
 
Movimentando o inimigo (parte 3) 
Agora, vamos manipular nosso script recém criado. 
1. Na aba Project, dê um duplo clique em Inimigo (dentro de Script). 
2. A ferramenta externa MonoDevelop para edição dos scripts será 
aberta. Vamos digitar o seguinte código nesta ferramenta: 
public class Inimigo : MonoBehaviour 
{ 
 void Start () 
 { 
 NavMeshAgent agente = GetComponent<NavMeshAgent>(); 
 agente.SetDestination (/*como saberemos a coordenadado fim do 
caminho?*/); 
 } 
} 
1. Precisamos criar um objeto no fim do caminho para utilizar como 
referência no nosso script. Clique com o botão direito dentro da 
aba Hierarchy e selecione Create Empty. Em seguida, renomeie o 
objeto criado paraFimDoCaminho. 
2. Selecione o objeto FimDoCaminho e em Inspector -> Transform clique 
no botão com a engrenagem (Settings) e selecione Reset Position. 
3. Agora reposicione o FimDoCaminho de modo que ele esteja no final 
do caminho mas continue dentro da NavMesh. 
4. De volta ao nosso script, agora podemos indicar 
o FimDoCaminho como destino para nosso objeto: 
public class Inimigo : MonoBehaviour 
{ 
 
 void Start () 
 { 
 NavMeshAgent agente = GetComponent<NavMeshAgent>(); 
 GameObject fimDoCaminho = GameObject.Find ("FimDoCaminho"); 
 Vector3 posicaoDoFimDoCaminho = 
fimDoCaminho.transform.position; 
 agente.SetDestination (posicaoDoFimDoCaminho); 
 } 
} 
1. Para testar nosso jogo e verificar que o Inimigo se move como 
esperamos, clique no botão Play localizado no centro da barra 
superior do editor como indicado na figura. Para encerrar o teste, 
clique novamente no mesmo botão. 
 
O que aconteceu com nosso inimigo? 
 
Refinando o movimento 
Dependendo de como o caminho foi construído, quantidade de curvas e 
espaço disponível, o Inimigo pode apresentar algumas dificuldades para 
se locomover. Vamos ajustar alguns parâmetros para tornar o movimento 
mais natural. 
1. Em Inspector -> Steering coloque Speed = 1 e em Inspector -> 
Obstacle Avoidance coloqueQuality = None. 
2. Teste estas mudanças de parâmetros clicando novamente no 
botão Play. 
3. Com o jogo rodando, selecione o Inimigo no Hierarchy e altere o 
parâmetro Speed em Inspector -> Steering. Perceba que podemos 
visualizar em tempo real a mudança de velocidade do Inimigo. 
4. Modifique o valor do parâmetro para qualquer coisa diferente 
de 1 e em seguida clique em Play para encerrar a execução do 
jogo. O que aconteceu com o valor do parâmetro Speed? 
 
Manipulando a luz ambiente 
Da mesma forma que o Unity cria uma câmera padrão, para que 
possamos ver nossa cena já é criada uma luz padrão 
chamada Directional Light! Precisaremos fazer apenas algumas 
alterações nela. 
 Em Hierarchy, selecione Directional Light. 
 Na aba Inspector, alteraremos seu nome para Sol. 
 Ainda com o nosso objeto selecionado, em Inspector -> 
Transform selecione o botão com uma engrenagem e, na 
sequência, Reset Position. 
 
 Com a posição zerada, em Inspector -> Transform -> Position, 
vamos deixar Y = 10. 
 Agora, podemos alterar sua rotação! Em Inspector -> Transform -> 
Rotation vamos colocar X = 35, Y = 45 e Z = 0. 
 Por fim, vamos alterar a intensidade da luz do Sol. Vamos 
em Inspector -> Light e colocar Intensity = 0.65. 
Por enquanto, vamos evitar que nossas luzes sejam recalculadas 
durante o jogo. Para isso, precisaremos abrir um menu novo 
chamado Lighting. 
Vá em Window -> Lighting e com o botão Scene selecionado, vá ao final 
dessa tela e desmarque a opçãoContinuous Baking. 
 
 
 
Construindo a torre e disparando 
mísseis 
Começando a batalha: nossa primeira torre 
Até o momento fizemos um cenário, manipulamos a câmera, luz e temos até um 
inimigo percorrendo um caminho, mas ainda falta o principal: a Torre! 
Durante a criação de um jogo, existem vários profissionais envolvidos de diversas áreas: 
programadores, designers, animadores, desenhistas, engenheiros de som, roteiristas... 
O modelo 3D de uma torre geralmente passa pelos desenhistas, animadores e designers 
para que os programadores possam incorporá-la ao jogo. Será que os programadores 
tem que esperar todo esse processo terminar para só então começar a trabalhar com a 
torre? 
Para evitar essa ociosidade e diminuir o tempo de criação de um jogo, enquanto o 
modelo da torre é feito, os programadores simulam o modelo com formas 3D mais 
simples, mas com as mesmas características da torre original! 
Dessa forma, quando o modelo 3D da torre estiver pronto, é só trocar a forma simples 
pelo modelo final. Isso é bastante fácil de fazer no Unity. 
Então, vamos começar a programar nossa torre, mesmo sem ter o modelo 3D pronto 
neste momento, para vermos como funciona esse fluxo. 
Como será essa torre? 
Nossa torre será composta por dois "cubos": um será o corpo da torre e o outro será 
o canhão da torre arranjados dessa forma: 
 
Como essa torre será um objeto do nosso jogo, lembre-se que ela será também 
um Game Object! Então, podemos criar as partes da nossa torre diretamente na 
aba Hierarchy. 
 
Agora temos um CorpoDaTorre e um CanhaoDaTorre, mas em nenhum lugar temos um 
objeto chamado, de fato,Torre. Caso queiramos mover todas as partes da torre, 
precisaríamos selecionar uma a uma, e se nosso objeto for composto por 20 partes 
diferentes? 
Para gerenciarmos melhor nossos objetos e transformá-los num único corpo, podemos 
criar um outro Game Object cuja única função será agrupar as diversas partes do nosso 
objeto composto. Mas qual Game Object serviria para essa função? Podemos criar mais 
um Cube, ou uma Sphere...? 
Veja que temos a possibilidade de criar um Empty Game Object, que pode ser usado 
justamente para agrupar outros objetos! 
Com esse Empty Game Object criado, podemos simplesmente colocar as partes da 
torre em seu interior e chamá-lo deTorre. 
 
Dessa forma, podemos arrastar e fazer qualquer configuração à torre como um todo, 
sem ter que repetir cada configuração para todas as suas partes. 
Míssil 
Criamos nossa torre, mas até o momento ela não faz nada; nossos inimigos podem andar 
tranquilamente na sua frente que nada acontecerá. Para mudar essa situação, vamos 
tornar nossa Torre um pouco mais perigosa fazendo-a disparar mísseis! 
Vamos trabalhar com um objeto simples que representará nosso míssil: um Cube. 
A diferença dessa vez está na seguinte pergunta: quem será o responsável por criar 
esse Game Object? O jogador já verá criados todos os mísseis que nossa torre pode 
disparar? 
Como nossa Torre será a responsável por disparar o Missil, temos que torná-lo um 
objeto instanciado dinamicamente no nosso jogo: um prefab. 
Prefab em detalhes 
Imagine que tenhamos um Game Object criado para cada Missil a ser disparado pela 
nossa Torre, mas agora queremos alterar o tamanho desses mísseis. Como os Game 
Objects são independentes dos outros (mesmo que tenham o mesmo nome), se 
quisermos alterar um atributo de um Game Object, teríamos que replicar essa alteração 
em todos os outrosGame Objects da nossa cena. 
Para não precisarmos fazer esse trabalho, o Unity possui um tipo de objeto 
chamado Prefab que permite armazenarmos um Game Object juntamente com todos os 
seus componentes e atributos. Então, quando precisarmos criar um Game Object a partir 
de um prefab, basta instanciar esse prefab usando o método: 
Instantiate (meuPrefab); 
Uma grande vantagem do uso de prefabs é que qualquer alteração feita num prefab é 
refletida para todos os objetos na cena instanciados a partir dele! 
Disparando mísseis 
Precisamos definir o comportamento do responsável em disparar mísseis, mas quem 
seria esse responsável? A própriaTorre! 
Então, vamos criar um script C# chamado Torre que conterá o comportamento da 
nossa torre. Como todo script que define o comportamento de um Game Object, esse 
deverá também ser filho de MonoBehaviour: 
public class Torre : MonoBehaviour 
{ 
 
} 
Logo que o objeto Torre aparecer na cena, vamos fazê-lo disparar um Missil. Então, 
vamos usar o próprio métodoStart do MonoBehaviour para instanciar nosso prefab: 
public GameObject prefabDoMissil; 
 
void Start() 
{ 
 Instantiate (prefabDoMissil); 
} 
Neste momento, como o nosso script Torre sabe quem é o prefab que representa 
o prefabDoMissil? Ele simplesmente não sabe! Precisamos, agora, vincular 
nosso prefab a esse atributo. 
Usaremos a própria interface do Unitypara isso: 
 
Tornando o ponto de disparo relativo à torre 
Ao chamar o método Instantiate passando um prefab, por padrão o Game 
Object instanciado é posicionado de acordo com o atributo position do prefab. Ao 
mover a Torre, como não alteramos a posição do nosso prefab, o Missilcontinuou 
sendo disparado da posição anterior. 
Mas sempre teremos que lembrar de posicionar o Missil perto da Torre? E se tivermos 
mais de uma Torre, onde oprefab do Missil ficará posicionado? 
Para resolvermos isso, vamos criar na nossa Torre um ponto de disparo, que usaremos 
como origem dos mísseis instanciados por essa Torre. Dessa forma, 
cada Missil disparado por uma Torre saberá em qual ponto deverá nascer. 
Como o ponto de disparo não é nada além de um ponto, podemos criar um Empty Game 
Object para representá-lo. Além disso, como o ponto de disparo pertence 
ao CanhaoDaTorre, podemos explicitar isso colocando o ponto dentro do canhão na 
hierarquia: 
 
Como usaremos esse ponto no Instantiate? 
Agora, podemos usar uma versão mais "inteligente" do método Instantiate, que 
recebe a posição onde o prefab será instanciado e uma rotação inicial também: 
Instantiate (prefab, posicao, rotacao); 
Mas, para saber a posicao, precisamos encontrar nosso PontoDeDisparo. Para isso, 
podemos usar o método Findpassando o nome do Game Object desejado e, na 
sequência, obter sua posição: 
GameObject pontoDeDisparo = 
 this.transform.Find 
("CanhaoDaTorre/PontoDeDisparo").gameObject; 
Vector3 posicao = pontoDeDisparo.transform.position; 
Por fim, podemos atribuir uma rotação que o objeto instanciado terá. Podemos usar a 
própria rotação contida no prefabchamando transform.rotation: 
GameObject pontoDeDisparo = 
 this.transform.Find 
("CanhaoDaTorre/PontoDeDisparo").gameObject; 
Vector3 posicaoDoPontoDeDisparo = pontoDeDisparo.transform.position; 
Instantiate (projetilPrefab, posicaoDoPontoDeDisparo, 
transform.rotation); 
Com isso, somos capazes de disparar mísseis sempre na mesma posição relativa à 
torre. 
Implementando a movimentação do míssil 
Conseguimos disparar o Missil, mas ainda ele fica "congelado" na frente do canhão da 
nossa torre. Agora, vamos fazê-lo se movimentar pelo campo de batalha. 
Como faremos para nosso Missil se movimentar? Estamos falando de um 
comportamento que somente nosso Missilterá, então, precisaremos de um script 
associado ao nosso Game Object! 
Vamos criar um script C# chamado Missil, que deverá ser filho 
de MonoBehaviour para garantir que esse comportamento será aplicado ao nosso objeto 
do jogo: 
public class Missil : MonoBehaviour 
{ 
 void Start () 
 { 
 
 } 
 
 void Update () 
 { 
 
 } 
} 
Por padrão, o Unity já popula nossa classe com os métodos Start e Update. Já vimos 
antes que o Start é chamado sempre que nosso objeto for criado, mas e o 
método Update? 
O método Update 
Todo MonoBehaviour possui o método Update, que é chamado pelo Unity 
a cada frame do jogo. Essa característica doUpdate permite implementarmos 
atualizações de qualquer tipo em um Game Object com a garantia de que será efetuada a 
cada frame do nosso jogo! 
Para mover o Missil, precisaremos reposicionar nosso objeto a cada frame do jogo, 
então esse será um uso perfeito para o método Update. Mas como será feita essa 
alteração de posição? 
void Update () 
{ 
 Vector3 posicaoAtual = transform.position; 
 //Como alteraremos essa posicaoAtual? 
} 
Podemos fazer nosso objeto se mover para a frente com uma velocidade constante de 10 
metros. Por convenção, o eixo Zde qualquer game object é tratado como a sua "frente". 
Basta capturarmos o eixo Z e seremos capazes de mover nosso objeto para a frente. 
Para facilitar, todo GameObject já possui uma forma de obtermos especificamente o 
eixo Z. Basta fazer: 
Vector3 frente = transform.forward; 
Agora é só usar essa frente e multiplicar pela nossa velocidade para sabermos o 
quanto temos que mover nosso objeto: 
private float velocidade = 10; 
 
void Update () 
{ 
 Vector3 posicaoAtual = transform.position; 
 Vector3 frente = transform.forward; 
 Vector3 deslocamento = frente * velocidade; 
} 
Agora, podemos adicionar esse deslocamento à posicaoAtual do nosso GameObject: 
private float velocidade = 10; 
 
void Update () 
{ 
 Vector3 posicaoAtual = transform.position; 
 Vector3 frente = transform.forward; 
 Vector3 deslocamento = frente * velocidade; 
 transform.position = posicaoAtual + deslocamento; 
} 
Então, a cada frame movemos nosso GameObject em 10 metros. Será que isso é 
suficiente para garantir um deslocamento constante? 
Frames não são constantes 
Um frame nada mais é do que a exibição de um único instante do jogo. Porém, para esse 
frame ser exibido, muitos cálculos devem ser efetuados pela GPU, e esses cálculos não 
possuem um tempo fixo para serem encerrados; dessa forma, um frame pode demorar 
mais do que outro para ser exibido! 
No nosso caso, como estamos deslocando o GameObject com uma velocidade de 10, na 
realidade estamos dizendo que queremos alterar nosso objeto com uma velocidade de 10 
metros por frame em vez de 10 metros por segundo. 
Para corrigir isso, o próprio Unity já oferece uma forma de compensar esse tempo de 
cálculo de cada frame: a classeTime. 
Usando Time para compensar o frame 
Usando o atributo deltaTime da classe Time, podemos capturar quanto tempo demorou 
entre a exibição do frame atual e o anterior. E essa informação pode ser usada para 
tornar nossa velocidade independente da taxa de frames exibidos: 
private float velocidade = 10; 
 
void Update () 
{ 
 Vector3 posicaoAtual = transform.position; 
 Vector3 frente = transform.forward; 
 Vector3 deslocamento = frente * velocidade * Time.deltaTime; 
 transform.position = posicaoAtual + deslocamento; 
} 
Disparando vários mísseis 
Em vez de disparar apenas um único Missil, podemos fazer nossa Torre disparar 
mísseis em um intervalo fixo. Então, olhando o script da nossa Torre, já podemos fazer 
uma alteração logo de cara: colocar o comportamento de disparo logo no Update! 
public class Torre : MonoBehaviour 
{ 
 void Update () 
 { 
 Atira (); 
 } 
} 
Mas agora, a cada quanto tempo nossa Torre atira? Sempre que o método Update for 
chamado, o que é bastante rápido! 
Para podermos parametrizar o tempo do disparo, vamos contar com o Time.time, que 
permite obtermos o tempo desde o início do jogo: 
private float momentoDoUltimoDisparo; 
 
public float tempoDeRecarga = 1f; 
 
private void Atira () 
{ 
 float tempoAtual = Time.time; 
 if (tempoAtual > momentoDoUltimoDisparo + tempoDeRecarga) { 
 momentoDoUltimoDisparo = tempoAtual; 
 
 // Dispara... 
 } 
} 
Então, sempre que estiver passado um intervalo tempoDeRecarga entre o tempoAtual e 
o momentoDoUltimoDisparo, podemos disparar um míssil! 
Mísseis teleguiados 
Conseguimos disparar mísseis num intervalo fixo, porém nossos mísseis sempre 
caminham para a frente. Desse jeito munca seremos capazes de acertar algum inimigo. 
Vamos fazer algo melhor: logo após serem disparados, nossos mísseis irão seguir o 
inimigo! 
Como nosso Missil sempre anda para a frente, podemos a cada frame corrigir a sua 
rota para sempre apontá-lo para a posição atual do inimigo. Isso será feito num método 
chamado AlteraDirecao no próprio script do Missil: 
void Update () 
{ 
 Anda (); 
 AlteraDirecao (); 
} 
Nesse método AlteraDirecao precisamos fazer nosso Missil apontar para o alvo. Se 
ele sempre estiver apontando, ao caminhar para a frente, cada vez estará mais perto do 
alvo, dando a ideia de ser "teleguiado". 
Mas como faremos o Missil sempre apontar para o alvo? 
Podemos pegar o vetor que representa a direção atual do míssil e corrigí-lo para apontar 
para a direção do inimigo. Como ambos são vetores, podemos subtraí-los: 
 
Ao fazer essa subtração, o vetor resultanterepresenta a nova direção do míssil, 
justamente a "correção" que estávamos procurando! 
private void AlteraDirecao() 
{ 
 Vector3 direcaoDoMissil = transform.position; 
 Vector3 direcaoDoInimigo = alvo.transform.position; 
 
 Vector3 novaDirecao = direcaoDoInimigo - direcaoDoMissil; 
} 
Temos a nova direção. Só precisamos fazer o Missil rotacionar para 
essa novaDirecao. Podemos fazer isso usando o método LookRotation da 
classe Quaternion atribuindo isso para a rotation do próprio GameObject: 
transform.rotation = Quaternion.LookRotation (novaDirecao); 
 
Construindo a primeira torre 
Vamos criar um novo objeto no nosso jogo: a torre! Como nossa torre 
será composta por cubos, vamos criar um novo3D Object clicando com o 
botão direito dentro de Hierarchy e 3D Object -> Cube. 
 
 Com o Cube selecionado no Hierarchy, vamos alterar seu nome 
para CorpoDaTorre lá na aba Inspector. 
 Vamos também alterar sua posição. Em Inspector -> Transform -> 
Position vamos colocar X = 0, Y = 0.65 e Z = 0 
 Por fim, vamos redimensionar esse cubo. Em Inspector -> 
Transform -> Scale X = 0.5, Y = 1.3 e Z = 0.5 
Podemos melhorar nossa torre. Em vez de termos somente 
o CorpoDaTorre, vamos criar também um outro cubo que será 
o CanhaoDaTorre! 
 Crie um novo objeto 3D clicando com o botão direito em Hierarchy 
-> 3D Object -> Cube e o renomeie paraCanhaoDaTorre. 
 Em Inspector -> Transform -> Position, deixe X = 0, Y = 1.55, Z = 
0 
 Agora, em Inspector -> Transform -> Scale, vamos colocar X = 
0.25, Y = 0.25, Z = 1 
Pronto! O que será que acontecerá se movermos apenas 
o CanhaoDaTorre pelo nosso jogo? 
 
Agrupando game objects 
Temos dois objetos independentes, mas na realidade esses objetos são 
partes de um objeto em comum, a nossa torre. Vamos dizer isso para o 
Unity. 
 Clique com o botão direito em Hierarchy -> Create Empty. 
 Vamos renomear esse objeto para Torre. 
 Com a Torre selecionada, em Inspector -> Transform -> Position, 
deixe X = 0, Y = 0, Z = 0 
Agora, é só arrastar os objetos CorpoDaTorre e CanhaoDaTorre para dentro 
do objeto Torre! Dessa forma, temos um objeto composto por vários 
outros objetos. 
Na tela do jogo, o que acontece ao arrastar o objeto Torre? 
 
Criação do míssil da torre 
Neste momento, nosso míssil será um outro cubo. Então, vamos 
construí-lo? 
 Clique com o botão direito em Hierarchy -> 3D Object -> Cube. 
 Não esqueça de renomear esse objeto para Missil. 
 Selecione o Missil na aba Scene e arraste-o para a frente do 
canhão da nossa Torre. 
 Vamos diminuir um pouco o tamanho desse Missil em Inspector -
> Transform -> Scale com os valores X = 0.2, Y = 0.2 e Z = 0.4 
Agora, vamos organizar a estrutura de pastas do nosso jogo para que 
nossos elementos não fiquem bagunçados! 
Clique com o botão direito em Project -> Create -> Folder e renomeie 
essa pasta para Prefabs. Agora, é só arrastar nosso Missil para dentro 
dessa pasta Prefabs. 
Veja que, neste momento, temos dois Missil: um deles na 
aba Hierarchy e outro dentro de Project/Prefabs. Como nossos mísseis 
deverão ser criados pela Torre, podemos deletar o Missil da 
aba Hierarchy! 
 
Criando o script da torre 
Para dar vida à nossa Torre, precisaremos de um script C#. 
 Vamos selecionar nossa Torre na aba Project. 
 Agora, vamos em Inspector -> Add Component -> New Script e 
chame-o de Torre. Arraste esse script para dentro da 
pasta Scripts. 
 Vamos abrir esse script. Dê um clique duplo 
em Project/Scripts/Torre. 
 Com o script aberto, remova o método Update. 
No fim, nosso script Torre, deverá estar assim: 
public class Torre : MonoBehaviour 
{ 
 void Start() 
 { 
 
 } 
} 
Quando esse método Start é chamado? 
 
Nossa torre pode disparar mísseis 
Agora, vamos fazer nossa Torre disparar um Missil! 
No nosso script Project/Scripts/Torre, vamos criar o método Atira que 
instanciará um novoProject/Prefabs/Missil: 
public class Torre : MonoBehaviour 
{ 
 
 public GameObject projetilPrefab; 
 
 private void Atira () 
 { 
 Instantiate (projetilPrefab); 
 } 
} 
Ainda não estamos chamando esse método Atira em nenhum lugar. 
Vamos chamá-lo dentro do Start da nossaTorre: 
public class Torre : MonoBehaviour 
{ 
 void Start () 
 { 
 Atira (); 
 } 
} 
 
Indicando o game object que deve ser 
disparado 
Nossa Torre ainda não pode atirar, pois não dissemos qual é 
o GameObject que representa nosso Missil. Para resolver isso, vamos 
selecionar Hierarchy/Torre. 
Agora, é só arrastar Project/Prefabs/Missil para Inspector -> Torre -> 
Projetil Prefab. 
 
Clique em Play e veja que nossa Torre atirará mísseis! 
Agora, movimente nossa Torre. De onde os mísseis são disparados 
agora? 
 
Aprimorando o disparo da Torre 
Ao mover a Torre, o disparo continua saindo do ponto anteriormente 
definido e não acompanha a nova posição doCanhaoDaTorre. Vamos, 
agora, deixar o ponto de disparo vinculado ao CanhaoDaTorre. 
 Em Hierarchy, vamos selecionar o CanhaoDaTorre com o botão 
direito e Create Empty. Agora, renomeie paraPontoDeDisparo. 
 Vamos alterar a posição do PontoDeDisparo indo em Inspector -> 
Transform -> Position e colocando X = 0, Y = -0.1 e Z = 0.8. 
Com isso, nosso PontoDeDisparo deverá ficar na frente do CanhaoDaTorre. 
 
Para disparar nosso Missil a partir do PontoDeDisparo, precisaremos 
alterar nosso script da Torre que está emProject/Scripts/Torre. 
Como é o método Atira o responsável por disparar nosso Missil, vamos 
modificá-lo: 
public class Torre : MonoBehaviour 
{ 
 
 private void Atira () 
 { 
 GameObject pontoDeDisparo = 
 this.transform.Find 
("CanhaoDaTorre/PontoDeDisparo").gameObject; 
 Vector3 posicaoDoPontoDeDisparo = 
pontoDeDisparo.transform.position; 
 Instantiate (projetilPrefab, posicaoDoPontoDeDisparo, 
Quaternion.identity); 
 } 
} 
 
Movimentando o Missil pelo campo 
Conseguimos disparar nosso Missil, porém ele ainda não pode se mover 
pelo campo. Para dar vida ao nosso objeto, precisaremos de um script! 
 Selecione Project/Prefabs/Missil e Inspector -> Add Component -> 
New Script. 
 Chame esse script de Missil e clique em Create and Add. 
Vamos abrir esse script e alterar o seu método Update: 
public class Missil : MonoBehaviour 
{ 
 
 private float velocidade = 10; 
 
 void Update () 
 { 
 Anda (); 
 } 
 
 private void Anda () 
 { 
 Vector3 posicaoAtual = transform.position; 
 Vector3 deslocamento = transform.forward * Time.deltaTime * 
velocidade; 
 transform.position = posicaoAtual + deslocamento; 
 } 
} 
 
DIsparando vários mísseis (parte 1) 
Em vez de disparar apenas um Missil, vamos fazer nossa Torre disparar 
vários deles. Para isso, vamos chamar o método Atira no Update do 
nosso script que está em Project/Scripts/Torre. 
Como apagamos esse método Update logo na criação do script Torre, 
podemos criá-lo agora: 
public class Torre : MonoBehaviour 
{ 
 void Start () { 
 // Podemos remover a chamada ao método Atira que estava 
aqui... 
 } 
 
 void Update () 
 { 
 Atira (); 
 } 
} 
Clique em Play e veja nossa Torre disparando vários mísseis! 
 
DIsparando vários mísseis (parte 2) 
Para definirmos um intervalo de disparo, precisamos novamente alterar 
nosso script Project/Scripts/Torre. 
Vamos contar o tempo entre um disparo e outro e, somente quando 
ultrapassar o tempoDeRecarga da Torre, dispararemos um novo Missil: 
public class Torre : MonoBehaviour 
{ 
 
 private float momentoDoUltimoDisparo; 
 
 [Range(0,3)] 
 public float tempoDeRecarga = 1f; 
 
 private void Atira () 
 { 
 float tempoAtual = Time.time; 
 if (tempoAtual > momentoDoUltimoDisparo + tempoDeRecarga) { 
 momentoDoUltimoDisparo = tempoAtual; 
 
 // Código que já tínhamos nesse método... 
 } 
 } 
} 
Clique em Play e veja os mísseis sendo disparados a cada segundo.Veja que colocamos [Range(0,3)] logo acima do tempoDeRecarga. Com o 
jogo rodando, clique no gameObject da Torre e olhe sua aba Inspector. 
Como o Tempo De Recarga é exibido? 
 
Mísseis teleguiados 
Vamos fazer nosso Missil perseguir o Inimigo. Para isso, vamos alterar 
nosso script emProject/Scripts/Missil para que o Missil ande e altere 
sua direção a cada intervalo de tempo. 
Vamos chamar um método que ainda não 
existe chamado AlteraDirecao: 
public class Missil : MonoBehaviour 
{ 
 
 [Range(0,5)] 
 public float velocidade; 
 
 void Update () 
 { 
 Anda (); 
 AlteraDirecao (); 
 } 
} 
No nosso método AlteraDirecao precisaremos rotacionar 
nosso Missil para a direção do alvo. Usando a classeQuaternion: 
public class Missil : MonoBehaviour 
{ 
 
 private void AlteraDirecao() 
 { 
 Vector3 posicaoAtual = transform.position; 
 
 // Quem é esse alvo? 
 Vector3 posicaoDoAlvo = alvo.transform.position; 
 
 Vector3 direcaoDoAlvo = posicaoDoAlvo - posicaoAtual; 
 transform.rotation = Quaternion.LookRotation (direcaoDoAlvo); 
 } 
} 
Nosso código já está quase pronto, mas como pegaremos esse alvo? 
Precisaremos trazer para nosso script o objeto Inimigo que está na cena 
do jogo. Então, logo ao instanciarmos esseMissil teremos que buscar 
esse Inimigo. 
Basta usarmos a o método Find da classe GameObject: 
public class Missil : MonoBehaviour 
{ 
 
 //... 
 private GameObject alvo; 
 
 void Start () 
 { 
 alvo = GameObject.Find("Inimigo"); 
 } 
 
 //Métodos anteriores... 
} 
Clique em Play e veja nossos mísseis perseguirem o Inimigo! Porém, o 
que acontece quando o Missil atinge oInimigo? 
 
Detectando colisões e destruindo 
inimigos 
Detectando colisões com Colliders 
Já temos uma torre capaz de disparar mísseis mas o que deve acontecer quando um 
míssil atinge um inimigo? 
A primeira coisa que precisamos fazer é detectar o momento em que ocorre uma colisão 
entre o míssil e o inimigo. 
Quando trabalhamos com modelos 3D mais detalhados é interessante aproximar a forma 
do modelo utilizando formas simples como cubos e esferas que permitem um cálculo 
mais eficiente das colisões entre todos objetos de uma cena. Por exemplo, veja o 
modelo abaixo: 
 
Note que o modelo é bastante detalhado e poderíamos até utilizá-lo para verificar as 
colisões mas isso teria um custo muito elevado de processamento no nosso jogo. 
Mesmo que estivéssemos fazendo uma simulação de corrida ultra-realista, não 
precisamos de um modelo tão detalhado para checar as colisões. 
Poderíamos tratar cada pneu como um cilindro de poucas faces e o corpo do carro como 
um ou mais cubos. Se o nosso jogo fosse ainda mais simples, como nos antigos jogos de 
corrida de arcade, poderíamos até mesmo tratar o carro inteiro como um único cubo 
como na figura! Como o cálculo das colisões é realizado a cada novo quadro de nosso 
jogo, ganhamos um tempo precioso simplificando essa tarefa. 
No Unity, esse modelo simplificado utilizado para o cálculo das colisões é chamado 
de collider. 
Para adicionar um collider a um objeto existente, só temos que selecionar o objeto e 
no Inspector, clicar em Add component -> Physics e escolher um dos 
vários colliders disponíveis. Depois basta configurar os parâmetros do colliderde forma 
a ajustá-lo à forma do modelo do seu game object. Note que os game objects do Unity 
que representam as formas primitivas já possuem os seus 
respectivos colliders adicionados. 
Como estamos interessados em detectar a colisão entre o míssil e o inimigo, e como 
esses dois objetos foram criados usando formas primitivas então não vamos precisar 
adicionar os colliders manualmente. 
Então agora só falta especificar o que devemos fazer quando uma colisão entre esses 
objetos ocorre. Primeiro vamos dizer para o Unity que estamos interessados em sermos 
avisados quando uma colisão ocorre. 
Fazemos isso selecionando o nosso Missil, por exemplo, e no Inspector -> Box 
Collider marcamos a opção Is Trigger. Com isso estamos dizendo que a área 
desse collider funcionará como um gatilho que irá disparar um método do script 
do Missil quando o objeto colidir com outro objeto que possua um collider. 
Agora precisamos editar o script associado ao Missil e implementar o 
método OnTriggerEnter que será chamado quando ocorrer a colisão. Neste método 
vamos aproveitar e destruir o Missil invocando o método Destroy passando o 
próprio game object do míssil como parâmetro: 
public class Missil : MonoBehaviour 
{ 
 
 // Códigos anteriores 
 
 void OnTriggerEnter (Collider elementoColidido) 
 { 
 Destroy (this.gameObject); 
 } 
} 
Tendo especificado o que fazer em caso de uma colisão do míssil, o que acontece 
quando testamos o jogo e um míssil atinge um inimigo? Nada! O que será que 
aconteceu? 
Para descobrir o que está acontecendo, precisamos entender um pouco melhor como o 
Unity lida com colisões. 
Simulando física e colisões com Rigidbodies 
No Unity, a detecção de colisão entre dois ou mais objetos é responsabilidade do 
simulador de física. Como nenhum objeto do Unity tem seus movimentos sujeitos às 
leis da física por padrão, então faz sentido que nossos objetos não sejam considerados 
na detecção de colisões. 
Então precisamos dizer ao Unity para tratar nossos objetos como objetos físicos! Para 
que isso aconteça é necessário dizer que um game object possui o comportamento de 
um Rigidbody. Um Rigidbody terá seus movimentos controlados pelo simulador de 
física do Unity, levando em conta fatores como sua massa, gravidade, entre outros. 
Sabendo disso, podemos fazer com que nosso Missil se comporte como 
um Rigidbody selecionando-o e clicando emInspector -> Add Component -> 
Physics -> Rigidbody. 
Mas se testarmos nosso jogo agora veremos que nossos mísseis caem imediatamente 
após terem sido disparados! Isso acontece porque agora ele está sofrendo a ação da 
gravidade! 
Vamos então corrigir isso definindo que queremos que ele seja tratado como um objeto 
físico mas não queremos que ele fique sujeito a ação da gravidade. Podemos definir isso 
indo no Inspector -> Rigidbody e desmarcando a opção Use Gravity. 
Agora sim nossos mísseis voltaram a ter o comportamento de antes! 
Testando o jogo agora, veremos que a colisão é detectada e o míssil é destruído como 
esperávamos mas o que acontece se um míssil atingir sem querer o cenário? 
Para chegarmos numa resposta, vamos selecionar o nosso objeto Chao e verificar os 
componentes desse objeto noInspector. Temos os 
componentes Transform, Terrain e Terrain Collider! Como esse objeto também 
tem umcollider, o míssil também será destruído se colidir com o terreno! 
Esse tipo de comportamento poderia tornar o nosso jogo mais realista mas dependendo 
da irregularidade do terreno, isso pode tornar o jogo difícil demais para o jogador. Nesse 
caso, seria interessante que o míssil ignorasse as colisões com o terreno... mas como 
poderíamos fazer isso? 
Categorizando nossos Game Objects com Tags 
Se prestarmos atenção no nosso método OnTriggerEnter do script Inimigo, veremos 
que esse método recebe como parâmetro um Collider. Esse Collider representa 
o collider do outro objeto que colidiu com o nosso. Então, nessa hora poderíamos 
perguntar para esse Collider quem é o objeto associado a ele! 
Então basta verificar se o nome do objeto com o qual colidimos é "Inimigo". Mas se 
implementarmos a verificação dessa forma, o que acontece se resolvermos alterar o 
nome do nosso inimigo? Teríamos que verificar todos os nossos scripts em buscas de 
referências ao nome antigo e substituí-lo pelo novo nome. 
No Unity existe uma maneira melhor de fazer isso. Ao invés de comparar os objetos 
utilizando seus nomes, podemos associar um objeto com uma Tag. Uma Tag é como um 
rótulo que podemos colocar em nossos objetos para agrupá-los. Assim podemosverificar se um objeto possui ou não uma determinada Tag para realizar alguma ação. 
Para criar uma nova Tag, selecionamos um objeto qualquer e no Inspector clicamos na 
caixa de seleção ao lado da palavra Tag indicada na figura abaixo: 
 
Depois selecionamos a opção Add Tag.... Com isso, abriremos uma nova tela 
no Inspector com opções referentes aos recursos de Tags e Layers. 
Em Inspector -> Tags, temos a lista de todas as tags que foram criadas no nosso 
projeto. Inicialmente, esta lista estará vazia e podemos criar uma nova tag clicando no 
botão + localizado no canto inferior esquerdo da lista como na figura abaixo: 
 
Com isso adicionamos uma nova entrada Tag 0 à lista de tags. Podemos alterar o nome 
dessa tag para algo que faça mais sentido no nosso caso, por exemplo, "Inimigo". 
Agora já temos uma nova tag definida mas como associamos essa tag com o nosso 
inimigo? Para isso, vamos selecionar novamente o Inimigo e 
no Inspector selecionar Tag = Inimigo. Pronto! Nosso Inimigo agora pertence à 
categoria "Inimigo". 
De volta ao script Inimigo, precisamos verificar se o objeto associado 
ao collider possui a tag "Inimigo". Para isso, utilizamos o método CompareTag do game 
object passando como parâmetro o nome da tag que queremos verificar: 
public class Missil : MonoBehaviour 
{ 
 
 // Códigos anteriores 
 
 void OnTriggerEnter (Collider elementoColidido) 
 { 
 if (elementoColidido.CompareTag ("Inimigo")) 
 { 
 Destroy (this.gameObject); 
 } 
 } 
} 
Se testarmos o jogo agora, veremos que o Missil só é destruído quando colide com 
o Inimigo. O único problema é que por enquanto nosso inimigo está invencível! 
Usando atributos para balancear o jogo 
Podemos fazer com que o inimigo seja destruído assim que for atingido por um míssil 
mas isso tornaria o jogo fácil demais. Ao invés disso, vamos adicionar um atributo no 
nosso inimigo para marcar a quantidade de pontos de vida que ele possui. Em seguida, 
vamos fazer com que nossos mísseis causem uma certa quantidade de pontos de dano ao 
atingir o inimigo. Quando o inimigo não tiver mais pontos de vida, então podemos 
destruí-lo. 
Começamos modificando o script Inimigo para adicionar um novo atributo. Para que 
possamos alterá-lo no editor do Unity, vamos tornar esse atributo público: 
public class Inimigo : MonoBehaviour 
{ 
 public int vida; 
} 
Isso funciona mas acabamos permitindo que qualquer objeto do nosso jogo também 
tenha acesso ao atributo vida doInimigo. Podemos alterar o modificador de acesso do 
nosso atributo para private mas o que acontece se fizermos isso? O editor do Unity 
também não terá mais acesso a esse atributo! 
Para manter o nosso atributo privado e ainda assim permitir que o editor tenha acesso a 
ele, podemos utilizar a anotação[SerializeField]. Dessa forma, podemos escrever 
nosso código assim: 
public class Inimigo : MonoBehaviour 
{ 
 [SerializeField] private int vida; 
} 
Utilizando essa mesma ideia, podemos alterar o script do Missil para indicar a 
quantidade de pontos de dano que ele causa: 
public class Missil : MonoBehaviour 
{ 
 [SerializeField] private int pontosDeDano; 
} 
Agora precisamos fazer com que o míssil reduza os pontos de vida do inimigo ao atingí-
lo. Qual dos nossos scripts é responsável por agir quando uma colisão acontece? O 
script Inimigo! Vamos alterar então o nosso métodoOnTriggerEnter para adicionar 
esse novo comportamento: 
public class Missil : MonoBehaviour 
{ 
 void OnTriggerEnter (Collider elementoColidido) { 
 if (elementoColidido.CompareTag ("Inimigo")) 
 { 
 Destroy (this.gameObject); 
 Inimigo inimigo = 
elementoColidido.GetComponent<Inimigo>(); 
 // aqui pedimos para o inimigo reduzir seus pontos de vida 
 } 
 } 
} 
No script acima, pedimos uma referência para o 
componente Inimigo do elementoColidido. Mas agora precisamos de alguma forma 
de alterar a quantidade de pontos de vida do inimigo. Como o atributo vida é privado, 
vamos ter que fornecer um método para deduzir uma certa quantidade de pontos de vida 
do inimigo: 
public class Inimigo : MonoBehaviour 
{ 
 public void RecebeDano(int pontosDeDano) 
 { 
 vida -= pontosDeDano; 
 if (vida <= 0) 
 { 
 Destroy(this.gameObject); 
 } 
 } 
} 
Note que nesse script já aproveitamos e destruímos o inimigo caso seus pontos de vida 
cheguem a 0. Agora que temos esse script, basta invocá-lo no script do Missil: 
public class Missil : MonoBehaviour 
{ 
 void OnTriggerEnter (Collider elementoColidido) { 
 if (elementoColidido.CompareTag ("Inimigo")) 
 { 
 Destroy (this.gameObject); 
 Inimigo inimigo = 
elementoColidido.GetComponent<Inimigo>(); 
 inimigo.RecebeDano(pontosDeDano); 
 } 
 } 
} 
Antes de testar o jogo, não podemos esquecer de definir os valores iniciais para os 
atributos vida e pontos de dano. Fazemos isso selecionando o objeto Inimigo e 
modificando o valor Inspector -> Inimigo -> Vida para 10. A mesma coisa para 
o Missil alterando o valor de Inspector -> Missil -> Pontos de Dano para 2. 
Para certificar que tudo funciona como o esperado, podemos testar o jogo novamente 
verificando se agora os inimigos resistem ao impacto de alguns mísseis antes de serem 
destruídos. 
Detectando colisões 
Primeiro vamos fazer com que o Missil disparado pela torre seja 
destruído quando colidir com algum outro objeto. 
 Na aba Project, selecione o Missil e em Inspector -> Box 
Collider marque a opção Is Trigger. Com isso dizemos para o Unity 
que a colisão deste objeto será utilizada como um gatilho para 
executar algum script. 
 Ainda no Inspector, clique no botão Add Component, selecione Physics 
-> Rigidbody e no componenteRigidbody que foi adicionado 
desmarque a opção Use Gravity pois não queremos que nosso míssil 
seja afetado pela gravidade. 
 Agora adicione um novo método no nosso script Missil para lidar 
com a colisão: 
public class Missil : MonoBehaviour 
{ 
 
 // Códigos anteriores 
 
 void OnTriggerEnter (Collider elementoColidido) 
 { 
 Destroy (this.gameObject); 
 } 
} 
Teste o jogo clicando no botão Play. O que acontece agora quando 
o Missil colide com algum outro objeto? 
 
Diferenciando colisões entre diferentes objetos 
Nosso Missil está sendo destruído sempre que colide com o cenário ou 
com um inimigo. Como nosso cenário tem muitas elevações e os 
inimigos se movem bastante, o Missil tem muita dificuldade em atingir o 
inimigo sem colidir com o terreno. 
Vamos modificar um pouco comportamento do Missil de modo que ele 
só seja destruído quando atingir um inimigo. 
 Primeiro precisamos ter alguma forma de distinguir entre o cenário e 
um inimigo. Para isso utilizaremos o recurso de Tags do Unity. 
Selecione o Inimigo e em Inspector -> Tag selecione Add Tag.... 
 Agora clique no botão + em Inspector -> Tags e preencha Tag 0 = 
Inimigo. 
 Selecione novamente o Inimigo na aba Hierarchy e em Inspector -> 
Tag selecione Inimigo. 
 Agora que o objeto Inimigo possui uma etiqueta Inimigo associada a 
ele, utilize essa nova informação para distinguir o objeto com o qual 
o Missil colidiu no método OnTriggerEnter: 
public class Missil : MonoBehaviour 
{ 
 
 // Códigos anteriores 
 
 void OnTriggerEnter (Collider elementoColidido) 
 { 
 if (elementoColidido.CompareTag ("Inimigo")) 
 { 
 Destroy (this.gameObject); 
 } 
 } 
} 
Destruindo o inimigo ao ser atingido 
Como o objetivo do Missil é destruir os inimigos, vamos fazer com que 
quando o Missil atinja um Inimigo, ambos sejam destruídos. Para isso 
altere o script Missil: 
public class Missil : MonoBehaviour 
{ 
 
 // Códigos anteriores 
 
 void OnTriggerEnter (Collider elementoColidido) 
 {if (elementoColidido.CompareTag ("Inimigo")) 
 { 
 Destroy (this.gameObject); 
 Destroy (elementoColidido.gameObject); 
 } 
 } 
} 
Teste o jogo novamente e veja que agora o inimigo é destruído quando é 
atingido pelo míssil. Mas o que acontece com os demais mísseis que 
tinham aquele inimigo como alvo? 
 
Destruindo os mísseis após um tempo fixo 
Vamos fazer com que os mísseis tenham um tempo de vida fixo e que 
eles se autodestruam quando esse tempo acabar. Modifique o 
script Missil para definir esse novo comportamento: 
public class Missil : MonoBehaviour 
{ 
 void Start () 
 { 
 alvo = GameObject.Find("Inimigo"); 
 AutoDestroiDepoisDeSegundos (10); 
 } 
 
 private void AutoDestroiDepoisDeSegundos(float segundos) 
 { 
 Destroy (this.gameObject, segundos); 
 } 
} 
Além disso, altere também o método Update do Missil para que ele não 
altere a direção do míssil se o alvo não existir mais: 
public class Missil : MonoBehaviour 
{ 
 
 // Códigos anteriores 
 
 void Update () 
 { 
 Anda (); 
 if (alvo != null) 
 { 
 AlteraDirecao (); 
 } 
 } 
} 
Agora teste novamente o jogo e observe o comportamento dos mísseis 
depois do inimigo ser destruído. 
 
Aumentando a resistência dos inimigos 
Nosso jogo agora ficou fácil demais já que um míssil é suficiente para 
destruir o inimigo. Vamos aumentar a resistência do inimigo atribuindo a 
ele pontos de vida e fazendo com que os mísseis sejam capazes de 
causar um número fixo depontos de dano. Quando os pontos de 
vida do inimigo chegarem a 0 então ele é destruído. 
 Adicione um atributo para marcar os pontos de vida no 
script Inimigo: 
public class Inimigo : MonoBehaviour 
{ 
 [SerializeField] private int vida; 
} 
 Analogamente, adicione agora um atributo para marcar os pontos 
de dano causados pelo Missil: 
public class Missil : MonoBehaviour 
{ 
 [SerializeField] private int pontosDeDano; 
} 
 Agora que temos esses atributos, podemos definir os pontos de 
vida iniciais do Inimigo e os pontos de dano 
doMissil pelo Inspector. Selecione o Inimigo na aba Hierarchy e 
em Inspector -> Inimigo -> Vidacoloque 10. Depois, selecione 
o Missil na aba Project e em Inspector -> Missil -> Pontos De 
Danocoloque 2. 
 Agora modifique o comportamento da colisão do Missil para que 
ele reduza os pontos de vida do Inimigoconforme a quantidade de 
pontos de dano que o Missil causa: 
public class Missil : MonoBehaviour 
{ 
 void OnTriggerEnter (Collider elementoColidido) { 
 if (elementoColidido.CompareTag ("Inimigo")) 
 { 
 Destroy (this.gameObject); 
 Inimigo inimigo = 
elementoColidido.GetComponent<Inimigo>(); 
 inimigo.RecebeDano(pontosDeDano); 
 } 
 } 
} 
 Modifique também o script do Inimigo para incluir um método que 
reduza uma certa quantidade de pontos de vida e destrua 
o Inimigo caso esses pontos cheguem a 0: 
public class Inimigo : MonoBehaviour 
{ 
 public void RecebeDano(int pontosDeDano) 
 { 
 vida -= pontosDeDano; 
 if (vida <= 0) 
 { 
 Destroy(this.gameObject); 
 } 
 } 
} 
Agora teste o jogo e note quantos mísseis são necessários para destruir 
um inimigo. 
 
Múltiplas torres para combater 
infinitos inimigos 
Gerando muitos inimigos 
Um único inimigo já não é mais suficiente para manter nosso jogo interessante já que 
ele pode ser destruído facilmente por nossa torre. Vamos melhorar isso gerando mais 
inimigos! 
Para começar, precisaremos de um objeto que ficará responsável por instanciar os novos 
inimigos. Como esse objeto não precisa ser visível para o jogador, que tipo de objeto 
iremos criar? Criaremos um game object vazio e associaremos a ele um script gerador 
de inimigos. 
Uma forma prática de criar um objeto vazio no Hierarchy é utilizar o 
atalho CMD+SHIFT+N (Mac) ou CTRL+SHIFT+N(Windows). Depois só 
precisamos renomeá-lo para algo que faça mais sentido 
como PontoGeradorDeInimigos. Como iremos gerar novos inimigos na posição desse 
objeto, vamos posicioná-lo no começo do nosso caminho tomando o cuidado de mantê-
lo sobre o terreno (coordenada Y = 0). 
No script que associaremos ao PontoGeradorDeInimigos, vamos precisar instanciar 
novos Inimigo mas antes disso, o que precisamos fazer com o Inimigo para que isso 
seja possível? O que o método Instantiate recebia como um parâmetro? Um prefab! 
Então o que precisamos fazer é transformar o Inimigo em um prefab. Para fazê-lo basta 
arrastar o Hierarchy/Inimigopara Project/Prefabs lembrando de remover 
o Hierarchy/Inimigo logo em seguida. 
Com o prefab preparado, vamos agora adicionar um script GeradorDeInimigos ao 
objeto PontoGeradorDeInimigos. Esse script deverá instanciar novos inimigos em 
intervalos regulares. Onde já fizemos isso antes? Nossa torre também faz algo bastante 
similar, ela instancia novos mísseis em intervalos regulares! Logo vamos ter um script 
bem parecido para o nosso gerador de inimigos: 
public class GeradorDeInimigos : MonoBehaviour 
{ 
 
 [SerializeField] private GameObject inimigo; 
 private float momentoDaUltimaGeracao; 
 
 [Range(0,3)] 
 [SerializeField] private float tempoDeCriacao = 2f; 
 
 void Update () 
 { 
 GeraInimigo (); 
 } 
 
 private void GeraInimigo () 
 { 
 float tempoAtual = Time.time; 
 if (tempoAtual > momentoDaUltimaGeracao + tempoDeCriacao) 
 { 
 momentoDaUltimaGeracao = tempoAtual; 
 Vector3 posicaoDoGerador = this.transform.position; 
 Instantiate (inimigo, posicaoDoGerador, 
Quaternion.identity); 
 } 
 } 
} 
Para que tudo funcione bem, só falta vincular o prefab do Inimigo ao nosso 
objeto PontoGeradorDeInimigos. Então selecionamos o PontoGeradorDeInimigos e 
arrastamos Project/Prefabs/Inimigos para Inspector -> Gerador De Inimigos 
-> Inimigo. 
Pronto! Já temos nosso gerador de inimigos em funcionamento! 
Escolhendo em quem atirar 
Até esse momento, nossa torre não precisava se preocupar em como escolher seu alvo já 
que tínhamos apenas um inimigo. Agora que temos infinitos inimigos o que fazer? 
Outro problema é que nossa torre hoje tem alcance infinito! Isso significa que a sua 
posição não faz diferença alguma no nosso jogo. Precisamos fazer com que mais prá 
frente, o posicionamento de uma torre se torne uma decisão importante para o jogador. 
Um jeito de conseguir isso é fazendo com que a torre tenha um raio de alcance limitado. 
Dessa forma, ela só poderia atirar nos inimigos que estivessem mais próximos. 
Podemos então adicionar um atributo raioDeAlcance ao script da Torre: 
public class Torre : MonoBehaviour 
{ 
 [SerializeField] private float raioDeAlcance; 
} 
Mas se agora a torre tem um raio de alcance, nem todos os inimigos do cenário são 
alvos válidos já que eles podem estar longe demais. Para levar isso em conta, vamos 
começar criando um método EscolheAlvo que inicialmente ficará responsável por 
pegar apenas os inimigos que estão na área de alcance da torre. 
Uma forma de fazer isso é utilizando o método 
estático FindGameObjectsWithTag do game object. Esse método devolve todos os 
objetos da cena que possuem uma tag específica. Para nossa sorte, já temos uma tag que 
distingue os inimigos dos demais objetos! Vamos então fazer essas alterações no 
script Torre: 
public class Torre : MonoBehaviour 
{ 
 private Inimigo EscolheAlvo() 
 { 
 GameObject[] inimigos = 
GameObject.FindGameObjectsWithTag("Inimigo"); 
 return null; 
 } 
} 
Com isso temos todos os inimigos da cena armazenados no array inimigos. Como 
fazemos agora para verificar se estes inimigos se encontram ao alcance da torre? Basta 
calcular a distância de cada um deles até a nossa torre e comparar com o raio de

Continue navegando