Movendo GameObjects com Rigidbody através do teclado em um ambiente 2D
E aí, pessoal! Dessa vez, vamos implementar a movimentação de um GameObject utilizando as
teclas A, W, S, D e as
setas direcionais do teclado.
|
Nave controlada pelo teclado com animação de movimentação
|
Para agilizar o nosso exemplo, vamos
utilizar como base o projeto desenvolvido no post
Importando Assets para o Jogo, que também pode ser baixado
aqui.
No nosso projeto base (uma versão minimalista de Space Shooter), nós já
temos os seguintes arquivos de Assets:
- Sprite da nave movendo para frente, chamado player;
- Sprite da nave movendo para a esquerda, chamado playerLeft;
- Sprite da nave movendo para a direita, chamado playerRight;
- Script para controlar a movimentação da nave, chamado Nave.
|
Assets disponíveis no projeto fornecido como base
|
Podemos ver também que na Hierarquia do projeto existe um GameObject
chamado
player, representando o personagem principal do nosso jogo: a
nave. E é esse GameObject que nós vamos movimentar. Ok?
|
GameObject player disponível na hierarquia do projeto base
|
O script Nave já é capaz de controlar a animação de movimentação da nave
(rodando para a esquerda e para a direta), quando as teclas
A ou
D são pressionadas, como podemos ver no script abaixo:
|
Script para animação de movimentação da nave
|
O resultado final em nosso exemplo, é a nave rotacionando visualmente, a partir da
troca de
sprites que é feita no
script de exemplo. Caso queira saber mais
detalhes sobre como esse exemplo foi desenvolvido, você pode
clicar aqui
e revisar nosso post
Importando Assets para o Jogo, onde esse projeto foi desenvolvido.
|
Animação de movimentação da nave
|
Agora que já temos o contexto do exemplo, vamos lá!
Movimentando GameObjects com RigidBody
Quando falamos em movimentar GameObjects na Unity, existem diferentes formas
de fazer isso, e cada uma delas é útil para um tipo diferente de mecânica. No
nosso caso, estamos trabalhando em um jogo no estilo Space Shooter, e
por isso nós vamos implementar a nossa movimentação utilizando o
Rigidbody para alterar a velocidade de movimentação da nossa
nave.
O que é um Rigidbody?
Rigidbody é o componente da Unity responsável por controlar a simulação de
física.
Ao adicionar o rigidbody em um GameObject, mesmo sem a adição de nenhuma linha
de código, o GameObject passará a ser controlado pelo sistema de física da
Unity, sofrendo ação da gravidade (sendo empurrado para baixo) e reagindo a
colisões com outros objetos, caso também possua um componente para colisão.
Existem dois tipos de Rigidbody disponíveis na Unity: Rigidbody e
Rigidbody2D.
O Rigidbody é utilizado em GameObjects que devem interagir com a física do
mundo 3D (tridimensional) da Unity, enquanto o Rigidbody2D, como o próprio
nome sugere, deve ser utilizar em GameObject que devem interagir com a física
2D, ideal para jogos 2D (com apenas duas dimensões).
Em nosso exemplo de Space Shooter, por ser um jogo 2D com movimentação
apenas em duas direções, nós vamos utilizar o Rigidbody2D.
Para adicionar um Rigidbody2D em nosso GameObject player, basta
executar os seguintes passos:
- Selecionar nosso GameObject player na Hirarquia;
-
Clicar no botão Add Component (adicionar componente) que
aparecerá na aba Inspector, juntamente com os demais componentes do
nosso GameObject;
-
Digitar o nome do componente que deseja adicionar para filtrar a lista de
componentes disponíveis. Neste caso, vamos digitar Rigidbody;
- Selecionar o componente Rigidbody2D.
|
Adicionando Rigidbody2D ao GameObject
|
Se apertar o botão
play para testar o nosso jogo logo após
adicionar o Rigidbody2D, poderemos notar que algo inesperado aconteceu...
|
Nave sofrendo ação da gravidade
|
A Nave caiu??
Sim...e isso se chama gravidade.
O Rigidbody2D é componente responsável por controlar a
simulação de física em um mundo 2D (bidimensional). Quando o nosso jogo
foi iniciado, o rigidbody começou a sofrer ação da física, mais
especificamente da gravidade, fazendo com que a nossa nave seja
puxada para baixo.
Entendi...mas a nossa nave deveria voar. Certo?!
Certo. Embora o
Rigidbody2D seja automaticamente afetado pela força da
gravidade, nós podemos desativar esse comportamento de uma forma bem simples.
No Inspector, com o
GameObject da nossa nave selecionado na
Hierarquia, podemos ver todas as propriedades do Rigidbody2D. Dentre
essas propriedades está a
Gravity Scale (escala da gravidade), que
define o
quanto a gravidade deve afetar esse Rigidbody2D
específico.
|
Propriedades do Rigidbody2D no Inspector, destacando a
escala da gravidade
|
Para evitar que o Rigidbody2D da nossa nave seja afetado pela força da
gravidade,
basta alterarmos o valor da escala da gravidade (Gravity
Scale)
para zero, fazendo com que a gravidade
não tenha nenhum efeito sobre o nosso GameObject.
|
Alterando a Escala da Gravidade para zero
|
Pronto, resolvido. Podemos testar o nosso jogo novamente e ver o que
acontece...
|
Nave sem ação da gravidade
|
Bem...na verdade, nada aconteceu, mas nesse caso isso é um bom sinal. O
nosso objetivo era fazer a nave não ser puxada para baixo pela gravidade e nós
conseguimos.
Agora que a nossa nave não está mais caindo no espaço, podemos começar a
trabalhar no script de movimentação. Vamos nessa?
Alterações no script Nave
Vamos começar analisando as mudanças que precisamos fazer no nosso script
Nave, para movimentar o nosso GameObject, utilizando física e o Rigidbody.
Para utilizar o componente Rigidbody2D em nosso script, precisamos primeiro
criar uma nova variável no script Nave, para ser associada ao Rigidbody do
nosso GameObject. Em seguida, vamos alterar o método Update para identificar
qual tecla está sendo pressionada pelo jogador e movimentar a nave na
diretação correspondente. Sendo assim, temos os seguintes passos para serem
implementados:
-
Criar uma variável do tipo Rigidbody2D para ser
associada com Rigidbody2D do nosso GameObject player;
-
Identificar qual tecla dentre as possíveis (A, W, S, D e setas
direcionais) está sendo pressionada;
- Mover a nave para a direção correspondente a tecla pressionada.
Passo 1 - Criando a variável Rigidbody2D
O primeiro passo é o mais simples e rápido. Basta editarmos o nosso script
Nave para adicionar uma nova variável do tipo Rigidbody2D logo abaixo
das variáveis já existentes. Aproveitei para nomear a nossa variável
também como rigidbody2d.
|
Adicionando a variável Rigidbody2D ao script Nave
|
Após a criação da nova variável, nós teremos cinco variáveis em nosso
script.
|
Script Nave após a adição da variável rigidbody2d
|
Se olharmos para o nosso script Nave no Inspector, veremos que a nossa
nova variável rigidbody2d parece em nosso script, porém, ainda sem valor
definido (
None).
|
Variável rigidbody2d no Inspector no script Nave
|
Agora que temos a nossa
variável, precisamos
associá-la com o Rigidbody2D que adicionamos anteriormente ao GameObject
player. Para isso, basta
arrastar o componente Rigidbody2D para a variável rigidbody2d do nosso
script Nave, e isso pode ser feito de forma simples a partir do Inspector.
|
Associando Rigidbody2D ao script Nave
|
Depois de associar o
componente Rigidbody2D com a nossa
variáviel rigidbody2d, estamos prontos para
utilizar o componente Rigidbody2D em nosso script e seguir para o
passo 2.
Passo 2 - Identificando a tecla pressionada
Para a movimentação da nossa Nave, nós precisamos identificar qual tecla
está sendo pressionada pelo jogador, e como você deve imaginar, essa
verificação precisa ser feita a cada frame do jogo para que
possamos reagir o mais rápido possível a uma mudança na tecla pressionada.
Para a nossa sorte, temos um método que permite executar ações a cada
frame. Qual? Qual? ...Sim! O método Update.
No projeto que utilizamos como base para este exemplo, o método
Update já estava sendo utilizado com a mesma finalidade
(identificar a tecla pressionada e reagir adequadamente), mas dessa vez
nós faremos isso de uma forma diferente.
Vamos ignorar o código existente no projeto base, por enquanto, para
focarmos na nossa nova abordagem de movimentação. Ok?
O que muda nessa nova abordagem de movimentação?
O nosso objetivo é identificar se qualquer uma das teclas A,
W, S, D ou uma das setas direcionais está sedo
pressionada. A Unity possui uma classe específica para nos ajudar com a
identificar os inputs (teclas pressionadas, cliques,
toques em telas e etc.) do jogador. Como você pode imaginar, essa classe
se chama Input.
A classe Input possui métodos como GetKey e
GetKeyDown que permitem verificar se uma tecla específica foi ou
está sendo pressionada, através de comandos como o exemplo abaixo, onde
conseguimos identificar se a tecla A está sendo pressionada:
void Update()
{
if (Input.GetKeyDown(KeyCode.A)) {
Debug.Log("Tecla A foi pressionada.");
} else {
Debug.Log("Tecla A NÃO está sendo pressionada.");
}
}
No nosso caso, onde temos um total de oito teclas para serem
verificadas, precisaríamos escrever uma grande quantidade de código para
identificar para qual direção o jogador desejar se movimentar.
Existe uma forma mais simples de fazer isso?...por acaso, existe!
Além dos métodos GetKey e GetKeyDown, a classe Input
também possui o método GetAxis que permite identificar se
alguma das teclas associadas aos eixos x e y está sendo
pressionada.
Espera! Como assim, teclas associadas aos eixos x e y?
É simple. A utilização das teclas A, W, S, D e das setas direcionais é um
comportamento comum no jogos, por isso, essa teclas já são automaticamente
associadas pela Unity, como sendo teclas relacionadas aos
eixos x (movimentação para os lados) e y (movimentação para
cima e para baixo).
Acho que estou entendendo, mas como isso funciona?
Utilizando o método GetAxis nós podemos informar qual dos
eixos nós queremos verificar e o método nos retornará um valor entre -1 e
1, dependendo das teclas pressionadas. Funciona assim:
Para utilizar o método GetAxis nós temos duas opções de eixo:
O eixo Horizontal identifica a movimentação para os lados, a
partir do uso das teclas A, D, seta para
esquerda ou seta para direita. Já o eixo Vertical,
identifica a movimentação para cima e para baixo, a partir do uso das
teclas W, S, seta para cima ou seta para
baixo.
A movimentação em cada um desses eixos pode variar entre -1 e 1, da
seguinte forma:
Quando falamos do eixo Horizontal, o jogador pode mover-se para a
esquerda ou para a direita. Certo? Sendo assim, caso
a movimentação seja para a esquerda, o método
GetAxis retornará um valor negativo, até chegar em -1. Por
outro lado (literalmente), caso a movimentação seja para a
direita, o método GetAxis retornará um valor
positivo, até chegar em 1.
O mesmo comportamento pode ser observado no eixo Vertical, onde
valores negativos são retornados pelo método GetAxis quando
o jogador pressiona uma tecla de movimentação para baixo, e
valores positivos são retornados quando o jogador pressiona uma tecla de
movimentação para cima.
Vamos ver o GetAxis em ação para entendermos melhor, utilizando o código
de exemplo abaixo para acompanhar a variação do valor do eixo
Horizontal quando as teclas A e D são pressionadas:
|
Código de teste com GetAxis
|
Ao executar o nosso jogo com o código exibido anteriormente, as
seguintes ações foram realizadas na ordem descrita abaixo:
-
Jogo iniciado sem tecla pressionada. O valor 0 é exibido
no Console.
-
Tecla A pressionada, fazendo o o valor variar de
0 até -1.
-
Tecla A liberada, fazendo o valor variar de
-1 até 0.
-
Tecla D pressionada, fazendo o valor variar de
0 até 1.
-
Tecla D liberada, fazendo o valor variar
de 1 até 0.
|
Variação dos valores do eixo Horizontal
|
Legal...mas como podemos usar isso para a nossa movimentação?
Agora que já estamos identificando a movimentação Horizontal,
precisamos apenas identificar também a movimentação Vertical,
antes de seguirmos para o próximo passo. Com base no exemplo anterior,
isso pode ser feito da seguinte forma:
void Update()
{
float movimentoHorizontal = Input.GetAxis("Horizontal");
float movimentoVertical = Input.GetAxis("Vertical");
}
-
A variável movimentoHorizontal possuirá um valor entre -1
e 1, indicando se o jogador deve mover para a esquerda ou para a
direita.
-
A variável movimentoVertical também possuirá um valor
entre -1 e 1, porém, indicando se o jogador deve mover para baixo ou
para cima.
Passo 3 - Movimentando a nave
Para executar a movimentação, nós utilizaremos o componente Rigidbody2D para alterar a velocidade do nossa nave, de acordo com as
teclas pressionadas pelo jogador. A alteração da velocidade do
Rigidbody2D pode ser feita através da propriedade
velocity (velocidade) do Rigidbody2D.
A propriedade velocity (velocidade) do Rigidbody2D é
representada por um Vector2. O Vector2 é um vetor bidimensional
(duas dimensões) que, neste caso, serve para definir a velocidade de
movimentação em dois eixos diferentes: x e y. O eixo
x representa a velocidade de movimentação
horizontal (para os lados) e o eixo y representa a
velocidade de movimentação vertical (para cima e para baixo).
A alteração da velocidade de um Rigidbody2D pode ser feita de forma
simples, criando um novo Vector2 com a velocidade de movimentação desejada
em cada um dos eixos (x e y), conforme o exemplo abaixo, onde o
Rigidbody2D moverá para o lado com velocidade -1 (esquerda).
|
Alterando a velocidade do Rigidbody2D para (-1, 0)
|
O resultado da adição desse trecho de código no método
Update da nossa nave, gera o seguinte resultado:
|
Nave movendo para a esquerda com velocidade -1
|
Está movendo! \o/
Muito bom...mas eu ainda não consigo controlar a nave. :(
Hora de controlar a nave
Pelo nosso exemplo anterior, conseguimos mover a nave definindo uma
velocidade fixa no Rigidbody2D, usando a propriedade
velocity (velocidade). Agora sabemos como podemos alterar a
velocidade da nave, precisamos apenas utilizar as variáveis
movimentoHorizontal e movimentoVertical que
criamos anteriormente para controlar a velocidade da nave de acordo com
as teclas pressionadas pelo jogador. Vamos tentar?
Conforme pode ser visto no trecho de código abaixo, precisamos alterar o
Vector2 que define a velocidade da nave para utilizar as
variáveis criadas anteriormente, a partir dos valores obtidos a partir
do método GetAxis:
void Update()
{
float movimentoHorizontal = Input.GetAxis("Horizontal");
float movimentoVertical = Input.GetAxis("Vertical");
this.rigidbody2d.velocity = new Vector2(movimentoHorizontal, movimentoVertical);
}
Hora de testar nossa movimentação!
|
Controlando a nave com as teclas (A, W, S, D e setas
direcionais)
|
É isso aí! Funciona! \o/
...mas está muito devagar :(
Definitivamente, precisamos
melhorar essa velocidade de movimentação.
...mas primeiro, vamos entender o que está acontecendo.
A velocidade de movimentação da nossa nave está sendo definida de acordo
com o valor retornado pele método GetAxis, que como já falamos
anteriormente, esse valor varia entre -1 e 1. Sendo assim, nossa
velocidade máximo é -1 (quando movendo para a esquerda ou para baixo) e 1
(quando movendo para a direita ou para cima). Para mover mais rápido,
precisamos criar um Vector2 com valores mais significativos
que -1 e 1. Felizmente, isso também é bem simples de ser
feito.
O que vamos fazer?
Nós vamos continuar utilizar GetAxis para identificar para onde o
jogador deseja mover a nave. Além disso, nós precisamos criar novas
variáveis calcular a velocidade de movimentação da nave, e utilizar
essa velocidade calculada para alterar o valor da propriedade
velocity do Rigidbody2D.
Como podemos fazer isso? Bem...criando algumas variáveis (e uma
constante).
Nossos próximos passos serão os seguintes:
-
Criar uma constante para determinar a velocidade máxima de
movimentação da nave;
-
Criar uma variável para determinar a velocidade de movimentação no
eixo X;
-
Criar uma variável para determinar a velocidade de movimentação no
eixo Y;
-
Alterar o código que define a velocidade do Rigidbody2D para utilizar
nossas duas novas variáveis;
Criar uma constante para determinar a velocidade máxima
Antes de calcularmos a velocidade que será aplicada ao Rigidbody2D em
cada um dos eixos, precisamos primeiro definir qual será a velocidade
máximo da nossa nave. Podemos definir a velocidade máxima da nossa nave
através de uma constante (já que esse valor não será alterado), e
utilizar esse valor para calcular a velocidade de movimentação da nave,
de acordo com o valor retornado pelo GetAxis.
// Velocidade máxima de movimentação da nave
const int velocidadeMaxima = 8;
Ao criar a constante velocidadeMaxima, decidi atribuir o valor
oito por achar que representa uma boa velocidade para a
nave. Após completarmos o exemplo, você poderá aumentar e/ou diminuir
esse valor de acordo com a velocidade desejada.
Criar uma variáveis para movimentação nos eixos X e Y
Agora vamos calcular a velocidade de movimentação em cada um dos eixos
(x e y) de acordo com o valor retornado pelo método
GetAxis (Horizontal e Vertical). Esse cálculo será
realizado a partir da multiplicação do valor retornado pelo método
GetAxis e o valor que definimos para a nossa
velocidade máxima, conforme o exemplo abaixo:
// Velocidade de movimentação no eixo X
float velocidadeX = (movimentoHorizontal * velocidadeMaxima);
// Velocidade de movimentação no eixo Y
float velocidadeY = (movimentoVertical * velocidadeMaxima);
Dessa forma, conforme o valor das variáveis movimentoHoziontal e
movimentoVertical oscila entre -1 e 1, o valor calculado
irá oscilar entre -8 e 8, por ser multiplicado pela nossa
constante velocidadeMaxima, que possui valor 8, fazendo com que
a nossa nave se mova 8 vezes mais rápido que anteriormente. Entendido?
Em seguida, basta alterarmos a criação do nosso Vector2 que define
a velocidade do Rigidbody2D, para utilizar nossas duas novas variáveis
velocidadeX e velocidadeY, conforme o trecho de código
abaixo:
this.rigidbody2d.velocity = new Vector2(velocidadeX, velocidadeY);
Com isso, o nosso Update completo fica assim:
void Update()
{
float movimentoHorizontal = Input.GetAxis("Horizontal");
float movimentoVertical = Input.GetAxis("Vertical");
// Velocidade máxima de movimentação da nave
const int velocidadeMaxima = 8;
// Velocidade de movimentação no eixo X
float velocidadeX = (movimentoHorizontal * velocidadeMaxima);
// Velocidade de movimentação no eixo Y
float velocidadeY = (movimentoVertical * velocidadeMaxima);
this.rigidbody2d.velocity = new Vector2(velocidadeX, velocidadeY);
}
E agora a nossa além de poder ser controlada pelo jogador, também está movendo
mais rápido
|
Nave movendo mais rápido
|
Então...chegamos ao fim? Quase...
Lembra do código do nosso projeto base, que deixamos de lado temporariamente?
Pois é! Esse é o momento de utilizarmos ele novamente. A partir de agora,
essas alterações não afetarão a movimentação da nave, mas serão um
extra para termos uma melhoria visual durante a movimentação.
Vamos lá?
Nós vamos realizar pequenas alterações no código da animação para podermos
utilizá-la com a nossa nova abordagem de movimentação. O código original da
animação da nave pode ser visto abaixo:
|
Trecho de código para rotação da nave, utilizada no projeto base
|
No código original, a rotação da nave era baseada na tecla pressionada. Se
o jogador pressionar a tecla
A, a nave vira para a esquerda. Se o jogador
pressionar a tecla
D, a nave vira para a direita. Caso nenhuma tecla seja
pressionada, a nave não vira para nenhum dos lados.
Esse mesmo código servirá para o nosso exemplo, porém, precisaremos alterar as
condições que verificam as teclas pressionadas, para utilizar a velocidade de
movimentação do jogador no eixo X, da seguinte forma:
-
Se a velocidadeX for menor que zero, a nave vira para a
esquerda;
-
Se a velocidadeX for maior que zero, a nave vira
para a direita;
Após essas alterações, o trecho de código da animação ficará assim:
if (velocidadeX < 0) {
// Mostra o sprite de movimentação para a Esquerda
this.spriteRenderer.sprite = this.spriteEsquerda;
} else if (velocidadeX > 0) {
// Mostra o sprite de movimentação para a Direita
this.spriteRenderer.sprite = this.spriteDireita;
} else {
// velocidade X = 0
// Mostra o sprite de movimentação para a Frente
this.spriteRenderer.sprite = this.spriteFrente;
}
Juntando esse novo trecho de código com as nossas alterações anteriores, teremos um método Update que permite o controle da nave a partir das teclas pressionadas pelo jogador e a animação de rotação durante a movimentação:
void Update()
{
float movimentoHorizontal = Input.GetAxis("Horizontal");
float movimentoVertical = Input.GetAxis("Vertical");
// Velocidade máxima de movimentação da nave
const int velocidadeMaxima = 8;
// Velocidade de movimentação no eixo X
float velocidadeX = (movimentoHorizontal * velocidadeMaxima);
// Velocidade de movimentação no eixo Y
float velocidadeY = (movimentoVertical * velocidadeMaxima);
this.rigidbody2d.velocity = new Vector2(velocidadeX, velocidadeY);
if (velocidadeX < 0) {
// Mostra o sprite de movimentação para a Esquerda
this.spriteRenderer.sprite = this.spriteEsquerda;
} else if (velocidadeX > 0) {
// Mostra o sprite de movimentação para a Direita
this.spriteRenderer.sprite = this.spriteDireita;
} else {
// velocidadeX = 0
// Mostra o sprite de movimentação para a Frente
this.spriteRenderer.sprite = this.spriteFrente;
}
}
E o resultado final no nosso jogo é o seguinte:
|
Nave controlada pelo teclado com animação de movimentação
|
Agora, sim! Nossa nave pode ser controlada pelo jogador usando das teclas A, W, S, D e setas direcionais, além de ter a animação de movimentação que adaptamos do nosso projeto base. Que tal?
O projeto completo desenvolvido nesse
post pode ser baixado
aqui.
Comentários
Postar um comentário