Melhorando o pulo
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.

Código Completo
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:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Jogador : MonoBehaviour
{
public Rigidbody2D rb;
public float forcaPulo = 700;
public LayerMask layerChao;
public float distanciaMinimaChao = 1;
private bool estaNoChao;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.UpArrow))
{
Pular();
}
}
void Pular()
{
if (estaNoChao)
{
rb.AddForce(Vector2.up * forcaPulo);
}
}
private void FixedUpdate()
{
estaNoChao = Physics2D.Raycast(transform.position, Vector2.down, distanciaMinimaChao, layerChao);
}
}Explicando o código
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:
void Update()
{
if (Input.GetKeyDown(KeyCode.UpArrow))
{
Pular();
}
}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
OnCollisionEnterouOnCollisionEnter2Dque é chamado sempre que umCollidercomRigidbodyencosta em outroCollider, mesmo que esse segundoCollidernão tenha umRigidbodyassociado.A segunda é utilizando um
Raycast, que desenha uma linha em uma direção e detecta se há algumColliderem 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.
Criando uma Layer para o projeto
Abra a
SampleScenee selecione oGameObjectChã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 8e escreva o nomeChão, como mostrado na figura a seguir.Pressione
Enterpara confirmar e selecione novamente oGameObjectChão.Em
Layer, clique na opçãoDefaulte 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.
Detectando se o Jogador está no 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:
public LayerMask layerChao;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étodoFixedUpdateda seguinte maneira:
private void FixedUpdate()
{
}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:
private bool estaNoChao;Volte para o
FixedUpdate.Dentro da chaves
{}, declare o seguinte conteúdo:
private void FixedUpdate()
{
estaNoChao = Physics2D.Raycast(transform.position, Vector2.down, 2f, layerChao)
}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 doTransformque está no mesmoGameObjectque o script em questão. Nesse caso, o scriptJogador.csestá noGameObjectdo Dinossauro, portanto, pegará a posição do Dinossauro.Vector2.down: É o mesmo que declararnew Vector2(0, -1), ou seja,0no eixoXe-1no eixoY. Como esse argumento doRaycastsignifica a direção da linha, esses valores indicam que a linha estará apontada para baixo.2f: O tamanho da linha.
Testando o Raycast
RaycastVolte para a Unity.
Selecione o
GameObjectdo Dinossauro.Na aba
Inspector, procure pelo componenteJogador (Script).Note que a variável
Layer Chaoapareceu (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
Nothinge altere paraChao. Isso fará com que a camadaChaoseja 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
DebugnoInspectorvá no canto superior direito e, embaixo deLayout, clique nos três pontinhos e selecione a opçãoDebug, como mostrado na imagem a seguir.
Visualizando se o Jogador está no Chão
Aperte o botão
Playou use o atalhoCtrl + P.Clique na aba
Game.Pressione a tecla
UpArrow(seta para cima) e verifique se a variávelestaNoChaoaltera 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
Raycaste altere o valor de2fparadistanciaMinimaChao. 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:
public float distanciaMinimaChao = 1f;Salve o script e volte para Unity.
Vá até o componente
Jogador (script)e verifique se a variávelDistancia Minima Chaoapareceu, 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.
Integrando a variável estaNoChao com a ação do pulo
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 umifpara checar se a variávelestaNoChaopossui o valortrue, da seguinte maneira:
void Pular()
{
if (estaNoChao)
{
rb.AddForce(Vector2.up * forcaPulo);
}
}Salve o script e volte para a Unity.
Aperte o botão
Playe teste o novo comportamento. Note que só conseguimos realizar um novo pulo quando o Dinossauro está próximo do chão.
Desativando a rotação do Rigidbody
RigidbodyEm 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
DebugdoInspector.Para isso, vá até a parte superior direita do
Inspectore, abaixo deLayout, clique nos três pontinhos.Selecione a opção
Normal.
No
Jogador, vá até o componenteRigidbody 2D.Clique em
Constraintse ative a opçãoFreeze Rotation (Z).
Com isto, o Dinossauro ficará sempre na mesma rotação para o eixo Z.
Salve a cena.
Concluindo
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.
Last updated
Was this helpful?