Programação de Scripts
Vamos agora dar sequência à programação de nosso jogo.
Usaremos o teclado, controle de jogo e mouse para interagir com o jogo,
criando mecânicas (funcionalidades) para saltar, atirar, correr, etc.
Primeiramente, vamos importar Weapon_&_Bullet_MuchoPixels.png para a
pasta Sprites da janela Project. Mude as propriedades conforme indicado ao
lado. Após as alterações, pressione [Apply].
Abra o Sprite Editor e mude a visualização para preto-e-branco. Selecione, na
lista de Slice (parte superior do Editor) o tipo Automatic e pressione o botão
[Slice] no fundo da janela de corte:
A separação dos sprites individuais será feita automaticamente.
15
Pressione o botão [Apply] no lado superior direito da janela do Sprite Editor e
feche essa janela.
Programação de Scripts
Mude o nome o personagem para Player, se não o mudou ainda.
No Asset do Sprite Atlas que fatiamos há pouco, selecione o primeiro
Sprite, que deve ser um pequeno círculo verde e o coloque na cena.
Mude seu nome para Bala.
Criaremos um novo script chamado, também, Bala. Associe esse script
ao objeto Bala da cena, por meio de arrasto.
Passemos, então, a trabalhar nesse script, codificando-o no Visual
Studio. Abra o script clicando duas vezes sobre ele no Inspector do
objeto Bala ou no arquivo indicado na pasta Scripts da janela Project.
Declare as duas variáveis globais da classe Bala (ou seja, dois atribu-
tos), de acesso público, conforme vemos no código ao lado. Salve.
A variável velocidade informará a rapidez com a qual a bala se moverá.
Ela foi iniciada com 2 para que esse valor apareça no Inspector como
um valor default.
A segunda variável é um Vector2, ou seja, um vetor bidimensional, que
informará a direção e distância que a bala deverá se mover, ao longo
desse vetor.
Visto no Inspector após ser salvo no Editor, o script Bala mostrará as
16
duas variáveis públicas como propriedades desse componente de
script.
Programação de Scripts
No método Update() do script Bala.cs codificaremos os comandos de programação que
indicarão ao jogo como se dará o movimento dos objetos associados ao script.
Acima calculamos o vetor de movimento do objeto associado ao script, multiplicando pela
velocidade a direção configurada no Inspector para a variável pública direcao.
Observe que essa direção foi normalizada, ou seja, a magnitude desse vetor foi considera-
da como sendo unitária (mede 1 unidade de distância). A propriedade normalized do Unity
faz os cálculos de normalização.
Assim, ao invés de estarmos movendo o objeto por uma medida qualquer, o moveremos
uma unidade por frame, mas sempre na direção (orientação, ângulo) definida pelo vetor
configurado (a proporção entre X e Y define um ângulo → teorema de Pitágoras, cálculo de
seno e cosseno baseado em catetos opostos e adjacentes → medidas de x e y).
Links sobre normalização de vetores:
Khanacademy
Alura 1
Alura 2 - matemática para jogos
17
Programação de Scripts
Para obter movimento suaves do objeto, sem que haja influência da velocidade do
processador gráfico (GPU), é importante multiplicar o resultado do vetor de movimento
pela fração de tempo decorrido desde o frame anterior.
Se, dentro do game loop, houver algum fator que torne variável o tempo de atualização
entre um frame e outro, será necessário homogeneizar o tempo entre a atualização dos
quadros. Isso pode ocorrer por diversos fatores, como carga de um asset em tempo de
jogo, ou demanda do processador em que o jogo está sendo executado, transferência de
dados para salvar o status do jogo, comunicação entre jogadores em ambiente multiplayer,
dentre outras situações que poderão impactar no desempenho.
Assim, multiplicar o vetor de movimento por Time.deltaTime faz essa homogeneização.
Em seguida, adicionaremos o vetor de movimento ao vetor de posição do objeto associado
ao script:
18
Programação de Scripts
Configure o X da propriedade Direcao no Inspector para 1, e deixe Y
valendo 0.
Se você executar o jogo agora, verá que a bola se moveu para a direi-
ta.
Para tornar nosso código mais intuitivo, Unity permite realizar a tarefa
de movimentação através do método Translate, como podemos ver na
alteração de código abaixo:
Vamos continuar a programação, testando várias teclas de controle.
Antes disso, desative o objeto Bala da cena, desligando seu Sprite 19
Renderer.
Programação de Scripts
Mude o nome da cena atual para Cena 01, caso ainda não esteja com esse nome.
Verifique se a janela Project do seu jogo possui o arquivo de cena Cena 02, e os
scripts FazAndar e LoadScene. Adicione-os a partir dos projetos anteriores caso não
os tenha no projeto atual. No caso da cena 02, será necessário copiá-lo diretamente
do Windows Explorer (ou equivalente no seu sistema operacional) para a pasta
Scenes da janela Project.
Associe o objeto Player com os eventos FazAndar e LoadScene, se isso não estiver
feito. Nesse caso, também preencha a propriedade Scene do script LoadScene com a
string Cena02.
Poderá ser necessário configurar Build Settings para que a Cena 02 seja acessível no
jogo.
Crie um novo script, chamando-o de TesteTeclas, na pasta Scripts da janela Projects.
Associe o script TesteTeclas ao nosso Player, arrastando o script até o Inspector
desse objeto.
Clique duas vezes no script para abrirmos o Visual Studio e vamos codificar o método
Update().
Primeiramente trataremos de eventos de mouse, usando a classe Input.
20
Programação de Scripts
A classe Input permite ao usuário controlar a aplicação usando um dispositivo, toques
ou gestos. Com essa classe, você poderá programar elementos da cena, tais como a
interface gráfica com o usuário ou um avatar de usuário para responder a entradas de
usuário de diferentes maneiras.
Unity suporta entrada de diferentes tipos de dispositivos de entrada, tais como:
• Teclado;
• Mouse;
• Joysticks;
• Controladores;
• Telas de toque;
• Recursos de sensoriamento de movimento de dispositivos móveis, como giroscópios ou
acelerômetro;
• Controladores de Realidade Virtual e de Realidade Aumentada.
Dica de emergência:
Se o Editor do Visual Studio ou VS Code
deixar de fazer o Intellisense, mova os
scripts para fora da pasta Scripts e os
traga novamente21
para ela. Será feita uma
atualização e o Intellisense retorna.
Programação de Scripts
Como já vimos anteriormente, podemos usar também controle pelo teclado. Isso é
feito com a chamada ao método GetKeyDown da classe Input.
Para ler o movimento executado em um eixo coordenado, use Input.GetAxis com um
dos eixos padrão: ”Horizontal” e “Vertical” são mapeados para o joystick, para as
teclas A, W, S, D e as teclas de setas.
“Mouse X” e “Mouse Y” são mapeados para o delta de mouse. Delta, aqui, corresponde
à diferença de coordenadas de jogo entre os momentos de movimento do mouse.
“Fire1”, “Fire2” e “Fire3” são mapeados às teclas Ctrl, Alt e aos três botões do mouse
ou a botões de joystick.
“Jump” está mapeada à tecla espaço, inicialmente.
Essas palavras identificam ações padrões que um jogador realizaria para controlar o
personagem, e podem ser configuradas na ferramenta Input Manager do Unity.
GetAxis, portanto, é uma boa escolha para tratar de comportamentos referentes a
movimentos dos objetos do jogo, quando controlados pelo jogador.
Use GetButton para outros tipos de ações, como criar eventos, abrir janelas, enviar
mensagens, etc.
É aconselhável que todas os tratamentos de entrada sejam feitos dentro do método
Update do objeto associado ao script. 22
Programação de Scripts
O parâmetro 0 do método GetMouseButtonDown() indica o botão esquerdo do mouse, 2
para o botão do meio e 1 para o botão da direita do mouse.
Temos, no evento Update, uma verificação de um evento de mouse. Mas também
temos, no script LoadScene, um tratador de evento OnMouseDown, também associado
ao Player.
Execute o observe a janela Console mostrando a mensagem acima sempre que você
clicar sobre o Player. Note, também, que a Cena 02 será carregada, como a deixamos
da última vez que a criamos.
Observe que o evento OnMouseDown de LoadScene foi
executado antes do método Update() de TesteTeclas.
23
Programação de Scripts
Abaixo, temos mais código que trata botões do mouse:
Quando executar, você perceberá que o script LoadScene
acaba atrapalhando a exibição das duas novas mensagens.
Portanto, remova esse script do Player (no Inspector, clique
nos três pontos verticais ao lado direito do script e escolha
a opção Remove Component.
Execute novamente e veja o resultado enquanto mantém o
botão da esquerda pressionado. 24
Programação de Scripts
Abaixo, temos código que trata o pressionamento de teclas do teclado, digitado no
método Update() após os ifs que tratam eventos de mouse:
Executando veremos as mensagens ao lado:
KeyCode é uma enumeração com a descrição de todas as teclas aceitas pelo Unity e
pré-configuradas.
Você pode usar também GetKey para detectar eventos de teclado enquanto a tecla
passada como parâmetro estiver pressionada, e GetKeyUp para detectar o evento em
que a tecla foi liberada.
O uso de mouse e de teclas já definidas acaba gerando pouca liberdade em jogos que,
eventualmente, sejam executados em dispositivos que não tenham teclado ou mouse
acoplados.
Unity não recomenda que se use esse tipo de método, embora estejam disponíveis.
Unity, portanto, fornece um sistema de configuração de entradas que permite que você
defina quais nomes e ações cada tipo de entrada realiza. 25
É o Input Manager (Gerenciador de Entrada), acessado no menu Edit | Project Settings.
Programação de Scripts
Vemos, ao lado, os itens do Input Manager,
sendo que, na figura da direita, os itens
Horizontal e Jump foram abertos, para você
observar como as teclas, setas e movimentos de
mouse e joystick são associados a propriedades
de movimentação.
Vemos, nessa figura, que o movimento
horizontal positivo é provocado pela seta
direita, e que o horizontal negativo é provocado
pela seta esquerda.
Da mesma maneira, as teclas d e a tem o
mesmo efeito.
Você pode configurar qualquer tipo de botão,
mudar os nomes atribuídos para os itens atuais.
Observe que há alguns nomes repetidos. Assim,
você pode ter diversas maneiras de executar o
mesmo movimento.
Unity poderá obter a tecla específica pressiona-
da, usando os métodos GetKey, ou usar, de 26
forma genérica, os nomes ao lado (Fire1, Fire2,
Vertical, etc).
Programação de Scripts
Veja o código abaixo. Nele usamos o método GetButtonDown, com a palavra Jump,
para detectar movimentação da barra de espaço ou a combinação de teclas que
tiver sido definida para fazer o player saltar.
Também detectamos a movimentação através de setas, letras W, A, S, D e movimen-
to de controlador de game, usando Input.GetAxis. O valor do movimento, horizontal
ou vertical, é um valor real que varia de -1 a 1. Observe na figura ao lado, que os
valores de horizontal e vertical vão diminuindo paulatinamente até chegarem em
zero. Unity faz isso para que os movimentos não mudem abruptamente de 0 para 1.
27
Note que a nuvem continua mudando de cor quando [Espaço] é pressionado, pois
essa nuvem está associada a outro script que trata a barra de espaço para ela.
Programação de Scripts
Vamos agora dar continuidade ao tratamento do objeto Bala.
Vamos aprender a destruí-lo depois de passado um tempo pré-determinado. Para
isso, abrimos o script Bala e declaramos uma variável pública que controle a dura-
ção da bala. Ela será pública para podermos configurá-la no Inspector em tempo de
design.
Ela se chamará tempoDeVida e terá um valor inicial como, por exemplo, 3f.
No tratador de evento Start, usaremos o método Destroy para informar ao Unity
quanto tempo depois de iniciada o objeto associado ao script deverá ser destruído.
Como vimos antes, this.gameObject é uma referência ao objeto de jogo associado
ao script. Destroy também pode destruir objetos buscados por GameObject.Find(
nome) ou GameObject.FindWithTag(qualTag).
28
No Inspector da bala, mude a velocidade para 1 e o tempo de vida para 2. Execute e
observe como a bala desaparece logo depois de começar a se mover.
Programação de Scripts
Vamos agora aprender a instanciar objetos em tempo de jogo. Por exemplo,
como criaremos balas quando isso for do interesse do jogador?
Primeiramente, vamos transformar a bala que está presente na cena em um
Prefab. Para isso, arraste o objeto Bala da janela Hierarchy para a pasta
Prefabs da janela Project. Observe que o objeto Bala na Hierarchy ficou azul, o
que indica ser Prefab. Mude o nome do prefab para “Bala prefab”.
Essa operação criará um objeto “pré-fabricado”, contendo tudo o que estiver
associado ao objeto da cena (no caso, a Bala), até mesmo scripts, materiais,
etc.
Um prefab é usado como modelo para criação (por design ou programação) de
novos exemplares do mesmo objeto, sempre que a mecânica do jogo assim o
exigir.
Para que não haja influência do objeto original no posicionamento do prefab,
entre no Inspector do prefab e faça reset de suas coordenadas no Transform.
Sempre que você alterar propriedades de um Prefab e pressionar o botão
[Apply], as modificações serão propagadas para todos os objetos da cena que
tenham esse prefab como modelo de criação.
Agora, apague o objeto Bala da cena (ou da Hierarquia), pois vamos instanciá-
lo em tempo de jogo. 29
Programação de Scripts
Antes vamos colocar, na cena, uma arma para disparar a bala. Escolha um dos
objetos de arma do sprite Atlas que configuramos anteriormente e o coloque
próximo ao player. Chame-o de Arma.
Nesse objeto, adicione um novo Componente script, chamado Arma. Arraste o
arquivo do script para a pasta Scripts da janela Project e digite o código abaixo:
No Inspector do objeto Arma, arraste o prefab da pasta Prefabs da janela 30
Project para a propriedade Prefab Bala do script Arma. Execute e veja que a
bala é instanciada e passa a se mover na cena.
Programação de Scripts
Acima, declaramos o atributo público prefabBala, que será visível no Inspector.
A ele arrastamos o prefab Bala Prefab para que seja usado no event Start().
O método Instantiate recebe como parâmetros o prefab que se deseja instanciar
em tempo de jogo, a posição onde ele será colocado (no caso acima, a posição
do objeto Arma), e o ângulo de rotação que se deseja dar ao objeto criado (no
caso, nenhuma rotação).
Nosso prefab tem configurada velocidade de 2, na direção direita ( x = 1) e
tempo de vida igual a 3.
Selecione o prefab na janela Project e mude X para 0 no script Bala.
Ao executar, observe que a bala aparece exatamente no centro da arma (ela
herda o Transform.Position da arma) e não se mexe mas, logo depois de 3
segundos, ela desaparece.
31
Programação de Scripts
Na arma, criaremos um ponto de tiro que não seja o seu centro, e sim a boca do
cano.
Para isso, clique na arma na janela Hierarchy e crie um objeto vazio subordinado à
arma.
Chame esse objeto de PontoDeTiro e o mova para o lado direito da arma, logo no
ponto onde a boca da arma está. Se quiser, coloque um ícone no Inspector desse
objeto para que ele seja visível na cena. Isso facilitará sua localização durante o
processo de design.
Tendo esse objeto PontoDeTiro, diremos ao script que ele será o ponto de partida
da bala. Resta saber para qual direção a bala se dirigirá. Isso pode ser determinado
a partir da escala X do objeto Arma. Se ele valer 1, significa que a arma aponta
para a direita. Se a escala X do objeto Arma valer -1, significa que a arma aponta
para a esquerda. Levando isso em conta, podemos direcionar o vetor de direção
para o mesmo sentido que a arma aponta. Observe a figura ao lado, onde a arma
aponta para a esquerda, quando Scale.X ficou com -1. Note que o PontoDeTiro
continua no mesmo local que estava antes, ou seja, na boca da arma.
Essa convenção é bastante usada em jogos 2D. Scale.X = 1 informa que o objeto
aponta para a direita. Scale.X = -1 informa que o objeto aponta para a esquerda.
Quando instanciarmos a bala, veremos para qual lado o objeto disparador aponta,32
para indicar a direção correta que a bala seguirá.
Programação de Scripts
No script Arma, declararemos a variável pública atirador, que indicará o objeto de jogo
que possui a arma (poderá ser um personagem, inimigo, carro, etc).
Também declararemos a variável privativa _pontoDeTiro, de tipo Transform.
Vimos que o evento Awake() é o melhor lugar para buscarmos objetos e criarmos
referências a eles. Assim, nesse evento, a variável _pontoDeTiro receberá a referência
ao objeto PontoDeTiro que criamos anteriormente.
No evento Start(), apagaremos o comando que instancia a bala, pois ela será
instanciada quando ocorrer um tiro.
33
Programação de Scripts
No script Arma, criaremos um novo método, chamado Atirar(), que fará o disparo da arma
de acordo com a ação esperada do usuário para esse fim.
Nesse método, verificaremos se o prefab de bala, o ponto de tiro e o atirador foram
configurados pelo desenvolvedor (no Inspector) e instanciamos um objeto bala, a partir do
prefabBala. Quando ele é instanciado, o segundo parâmetro de Instantiate() será a
coordenada (position) do ponto de tiro que definimos internamente à arma.
Em seguida, buscaremos o script Bala desse novo objeto, para mudar o valor da sua
propriedade direcao (para a esquerda ou para a direita), de acordo com o lado para o qual
o objeto que possui a arma está olhando.
34
Programação de Scripts
Sempre que for usar um prefab atribuído a uma variável pública (que será
visualizada como uma propriedade no Inspector), é importante verificar se ele é
diferente de null, pois o desenvolvedor pode ter deixado de atribuir um valor a essa
propriedade no Inspector.
Não mais faremos a instanciação da bala no evento Start() pois agora teremos um
evento que disparará a bala. Esse evento pode ser o pressionamento de uma tecla,
de um botão de controlador, de um botão do mouse ou outros modos de Input que
tenha sido definido no design da interface do jogo com o usuário.
Futuramente definiremos o atirador como um inimigo mas, neste momento, usare-
mos a própria arma para isso. Arraste o objeto Arma da janela Hierarchy para a
propriedade Atirador do script Arma.
Vamos executar o jogo e verificar para qual lado a arma atira a bala.
Como você poderá observar, nada acontecerá, pois ainda não criamos nenhuma
situação que chame o método Atirar() que codificamos anteriormente. Para testar
apenas, poderá chamar o método Atirar() de dentro do evento Start():
Como a arma foi deixada para a esquerda, a bala segui nessa direção.
Se Scale.X da arma fosse 1, a bala se moveria para a direita.
35
Programação de Scripts
Imagine que você deseja disparar a bala quando o botão de tiro (Fire1) for
pressionado. Esse botão vem pré-configurado como a tecla [Ctrl] esquerda.
Para detectar o pressionamento desse botão, criamos o código abaixo no evento
Update() :
Note que, se usarmos GetButton() ao invés de GetButtonDown(), como Unity
testará esse if durante todo o game loop e nossos dedos levam um certo tempo
para deixar o botão, enquanto ele estiver pressionado teremos uma espécie de
sombra na bala, que mostra que ela foi gerada várias vezes, pois Atirar() será
chamado várias vezes.
Com GetButtonDown() apenas o momento do pressionamento do botão é
testado, efetuando apenas uma chamada de Atirar(). Um comportamento
semelhante ocorreria com o uso de GetButtonUp(), disparado na liberação do
botão.
36
Programação de Scripts
Agora, vamos programar, no método Update(), o disparo do botão Fire2 (geralmente
a tecla Alt esquerda), quando dispararemos uma rajada de 3 tiros, separados por
algumas frações de segundo:
O método Invoke chama (invoca) o método cujo nome está no primeiro parâmetro, logo
depois de passar o tempo (em segundos) dado no segundo parâmetro, contado a partir do
início do Update().
Ao executar o jogo, veremos três tiros, saindo da arma, espaçados por 0.2 segundos. As
balas se autodestroem depois do tempo determinado no script Bala.
É importante autodestruir objetos que são criados em sequência, pois assim eles não
ficam diminuindo o desempenho do processador gráfico após terem saído da parte visível
da cena.
37
Programação de Scripts
Em seguida, aprenderemos uma técnica chamada Interpolação Linear, usada para
variar paulatinamente o valor de uma medida desde um valor inicial até um valor
final.
Por exemplo, podemos usá-la para fazer um objeto mudar de cor, de vermelho para
branco, durante um intervalo de tempo que definimos. Unity usará a Interpolação
Linear para fazer com que a cor varie da cor original até a cor final, no decorrer
desse intervalo, efetuando os cálculos necessários para definir cada cor intermediá-
ria.
Essa técnica pode ser aplicada em outras medidas, como valores reais, inteiros,
coordenadas, dentre outras.
38
Programação de Scripts
A Interpolação Linear é realizada pelo método Lerp, que pode ser chamado de várias
classes de objetos, como Color, Transform.
Vamos usar esse método na nossa Bala, para que ela mude de cor desde o momento
em que é lançada até estar próxima ao momento de se autodestruir. Dessa maneira,
o jogador saberá que poderá ser perigoso estar perto dessa bala quando ela for
“explodir”.
Faça as alterações abaixo no script Bala, logo depois da declaração de tempoDeVida:
39
Programação de Scripts
Continue alterando o script, agora no método Update(), depois da chamada ao
método Translate():
Acima se obtém o horário atual e se calcula o tempo decorrido desde o início
da execução (Start) para o objeto associado ao script.
Em seguida, se calcula a porcentagem do tempo decorrido em relação ao
tempo de vida configurado para o objeto associado ao script.
Logo depois, a cor da bala é recalculada, usando o método Lerp(), que recebe
como parâmetros a cor inicial, a cor final e a porcentagem da variação entre
uma cor e outra.
Agora temos que ir no Bala Prefab (janela Project, pasta Prefabs) e alterar a 40
cor inicial e a cor final no script Bala. Mude Tempo de Vida para 2.
Programação de Scripts
Ao executar o jogo, verá que a bala vai mudando de cor. Se isso não acontecer, volte
ao Bala Prefab e, na propriedade Color do Sprite Renderer, coloque o valor de Alpha
(transparência) igual a 255.
Observe como as balas vão ficando com o contorno mais avermelhado conforme
avançam no seu percurso. Esse é o efeito do Lerp.
41