Melhorando o pulo
Last updated
Last updated
Tá! Já temos o pulo funcionando, mas... percebe que quando apertamos a tecla de pular várias vezes em sequência, o dinossauro vira um foguete e vai ao infinito e além? Se fosse um jogo da NASA, tudo bem, mas como queremos reproduzir o comportamento exato do jogo oficial, precisamos corrigir isso. Partiu?
Nosso objetivo é fazer com que o dinossauro possa pular apenas quando estiver no chão e bloqueie novos pulos quando estiver no ar.
Ao longo dos capítulos a seguir, explicaremos o passo a passo para ajustar o pulo do dinossauro. Caso queira testar a implementação, você pode usar o código completo, disponível a seguir:
Abrindo o script podemos notar que já temos o código que detecta quando a tecla foi pressionada e o código que adiciona uma força ao Rigidbody
, fazendo com o que o dinossauro pule:
Para impedir que o dinossauro pule sempre que o jogador pressionar a tecla, precisamos validar quando dinossauro está no chão antes de adicionar uma força ao corpo.
Existem algumas formas de detectar se o jogador está no chão:
A primeira é utilizando o método OnCollisionEnter
ou OnCollisionEnter2D
que é chamado sempre que um Collider
com Rigidbody
encosta em outro Collider
, mesmo que esse segundo Collider
não tenha um Rigidbody
associado.
A segunda é utilizando um Raycast
, que desenha uma linha em uma direção e detecta se há algum Collider
em cima dessa linha desenhada.
A primeira abordagem funciona bem na maioria dos casos e geralmente é a abordagem utilizada em diversos tutoriais. Entretanto, quando utilizamos o OnCollisionEnter
, dependemos da colisão entre os dois objetos, fazendo com que um novo pulo só esteja liberado quando o jogador de fato toca o chão.
Quando estamos falando de game flow, podemos perceber que certos comportamentos ajudam o jogador a ter um fluxo de jogo que flui melhor e é mais natural. Quando liberamos um novo pulo para o jogador, mesmo que o GameObject
ainda não esteja tocando o chão, compensamos o fato do jogador apertar a tecla um pouquinho antes de tocar o chão, fazendo com que o pulo não seja uma ação tão punitiva caso o jogador erre o tempo e pressione a tecla um pouquinho antes da colisão acontecer.
Portanto, utilizaremos oRaycast
, desenhando ele para que comece na base do dinossauro e termine um pouco embaixo dele.
Essa linha irá detectar se há um objeto de chão (marcado com a layer Chão
) próximo, definindo que o dinossauro está no chão, mesmo que não esteja encostando nele diretamente.
Raycast - Projeta um raio em uma direção, a partir de uma posição.
**Layer (Camada) **- As camadas da Unity servem para organizar os objetos, permitindo alterar, entre outras funções, a ordem de renderização e a interação do sistema de física.
Abra a
SampleScene
e selecione oGameObject
Chão
.Na aba
Inspector
, procure pela opçãoLayer
, que estará com o valor definido comoDefault
, e clique para abrir a lista de opções.Clique na opção
Add Layer
.Clique no input de
User Layer 8
e escreva o nomeChão
, como mostrado na figura a seguir.Pressione
Enter
para confirmar e selecione novamente oGameObject
Chão
.Em
Layer
, clique na opçãoDefault
e altere para a camada que acabamos de criar.
Agora que definimos a nova camada no objeto, podemos utilizá-la para detectar colisões entre o Dinossauro e o Chão.
O primeiro passo para detectar se o Jogador está no Chão é definir qual é a layer que corresponde ao chão. Para isso, utilizaremos uma variável public
do tipo LayerMask
, que permite com que essa layer seja definida no Inspector
.
Abra o script do
Jogador
.Logo abaixo da variável
forcaPulo
, declare o seguinte conteúdo:
Como estamos trabalhando com física, é recomendado que as colisões entre Raycast
os objetos da cena sejam declaradas no FixedUpdate
.
Assim como o método Update
, o FixedUpdate
também é executado constantemente. Entretanto, a diferença é que o FixedUpdate
não é executado uma vez por quadro (frames per second) e sim num intervalo de tempo fixo que consiste em uma chamada a cada 0.02 segundos, resultando em 50 chamadas por segundo.
Logo após o término do método
Pular
, declare o métodoFixedUpdate
da seguinte maneira:
Antes de declarar o Raycast
precisamos de um local para guardar a informação de que o Dinossauro está ou não no chão. Para isso, declaramos uma variável pública do tipo bool
.
Logo após a variável
layerChao
, logo no começo do arquivo, declare o seguinte conteúdo:
Volte para o
FixedUpdate
.Dentro da chaves
{}
, declare o seguinte conteúdo:
Salve o script.
Para entender um pouco mais da declaração do Raycast
, precisamos entender cada pedacinho individualmente:
Estamos utilizando a seguinte declaração do Raycast
:
Physics2D.Raycast(Vector3 posicao, Vector3 direcao, float distancia, LayerMask layer)
Physics2D
: Pacote da Unity para trabalhar com física 2D.
Raycast
: Projeta um raio em uma direção, a partir de uma posição.
tranform.position
: Pega a posição atual do Transform
que está no mesmo GameObject
que o script em questão. Nesse caso, o script Jogador.cs
está no GameObject
do Dinossauro, portanto, pegará a posição do Dinossauro.
Vector2.down
: É o mesmo que declarar new Vector2(0, -1)
, ou seja, 0
no eixo X
e -1
no eixo Y
. Como esse argumento do Raycast
significa a direção da linha, esses valores indicam que a linha estará apontada para baixo.
2f
: O tamanho da linha.
Raycast
Volte para a Unity.
Selecione o
GameObject
do Dinossauro.Na aba
Inspector
, procure pelo componenteJogador (Script)
.Note que a variável
Layer Chao
apareceu (caso não esteja aparecendo, verifique se salvou o script ou se há erros no Console. Corrija os problemas até que a variável apareça corretamente).Clique na opção
Nothing
e altere paraChao
. Isso fará com que a camadaChao
seja definida como a camada de detecção de colisão peloRaycast
.
Note que a variável estaNoChao
não aparece, pois ela está definida com private
e a Unity exibe apenas variáveis que são public
ou que estão marcadas como [SerializeField]
, que cobriremos em outra oportunidade.
Para conseguir validar se o Raycast
está marcando corretamente quando o Jogador está no chão, precisamos visualizar essa variável. Para visualizar o conteúdo de variáveis privadas, precisamos ativar o modo Debug
do Inspector
.
Para ativar o modo
Debug
noInspector
vá no canto superior direito e, embaixo deLayout
, clique nos três pontinhos e selecione a opçãoDebug
, como mostrado na imagem a seguir.
Aperte o botão
Play
ou use o atalhoCtrl + P
.Clique na aba
Game
.Pressione a tecla
UpArrow
(seta para cima) e verifique se a variávelestaNoChao
altera o valor conforme o Jogador se afasta do chão.
Observe que a variável só fica com o valor true
quando o Jogador está muito próximo do chão. Para melhorar o game flow e permitir ao game designer testar diferente combinações de valores e ajustar o melhor valor possível, é interessante colocar uma variável pública no Inspector
que permite esse ajuste fino.
Volte para o script do
Jogador.cs
.Procure pela declaração do
Raycast
e altere o valor de2f
paradistanciaMinimaChao
. Note que essa variável ainda não existe e a IDE deve mostrar um erro.Precisamos declarar essa variável. Vá para parte superior do script e, logo após a variável
layerChao
, declare o seguinte código:
Salve o script e volte para Unity.
Vá até o componente
Jogador (script)
e verifique se a variávelDistancia Minima Chao
apareceu, como mostrando na imagem a seguir:
Agora basta ajustar o valor da variável para um que achar interessante, testando o jogo e validando se está com o game flow que acha interessante.
No nosso caso, ajustar a distância do chão para 0.8
funcionou de uma maneira interessante.
estaNoChao
com a ação do puloPara finalizar o script, precisamos colocar uma checagem logo antes de realizar a ação do pulo.
No script do
Jogador.cs
, vá até o métodoPular()
.Em volta da declaração do
AddForce
, adicione umif
para checar se a variávelestaNoChao
possui o valortrue
, da seguinte maneira:
Salve o script e volte para a Unity.
Aperte o botão
Play
e teste o novo comportamento. Note que só conseguimos realizar um novo pulo quando o Dinossauro está próximo do chão.
Rigidbody
Em alguns casos, o Dinossauro está rotacionando logo após o pulo, fazendo com que ele caia e fique com um comportamento estranho. Uma forma de resolver isso de maneira bem simples é desativando a rotação do componente Rigidbody
.
Primeiro, precisamos desativar o modo
Debug
doInspector
.Para isso, vá até a parte superior direita do
Inspector
e, abaixo deLayout
, clique nos três pontinhos.Selecione a opção
Normal
.
No
Jogador
, vá até o componenteRigidbody 2D
.Clique em
Constraints
e ative a opçãoFreeze Rotation (Z)
.
Com isto, o Dinossauro ficará sempre na mesma rotação para o eixo Z
.
Salve a cena.
Nesse tutorial trabalhamos com algumas funções do pacote de física da Unity, aprendemos como o Raycast
pode ser muito útil para detectar colisões entre camadas, entendemos que funções de física precisam ser declaradas no FixedUpdate
, descobrimos uma forma de visualizar a informação de variáveis privadas e descobrimos que existem várias maneiras de realizar o mesmo comportamento, mas que algumas permitem a construção de um game flow mais interessante.
Para finalizar, suba as modificações no GitHub
para que elas fiquem salvas na nuvem e você não perca o progresso de desenvolvimento do jogo.