Tutorial Snake 3D usando Unity - Parte 5
Iai galerinha, tudo tranquilo com vocês? Nossa pegada de hoje é fazer mais parte da lógica do movimento da cobra. Vou listar o que vamos aprender gora e vamos ver mais um caso do nosso divisor de águas.
Tasks
- Adição de uma nova parte da cobra;
- Movimento correto da nova parte da cobra.
Bem, nosso objetivo hoje será somente este. Pode parecer pouca coisa, mas vamos aprender hoje sobre listas encadeadas e isto pode ser um pouco complicado demais, por isso vamos prestar bastante atenção, e não esqueça que você pode sempre recorrer à ajuda nos grupos da comunidade.
1. Movimento correto da cobra
Antes da gente continuar, vamos conferir o estado atual do movimento e ver a questão dos colisores já que vamos precisar identificar que coletamos uma fruta.
Ual! Tem algo muito estranho aqui. Ao que tudo indica, estamos movendo pros lados mas este passo da cobra não me parece nada certo. Parece que o movimento está dando pequenos pulos, e não estamos colidindo com a fruta. Vamos corrigir essa parte dos pequenos pulos. Lá no trecho de código do movimento, na função OnTick do SnakeComponent.
void OnTick()
{
// TO DO: perform action
transform.position += direction * speed * Time.deltaTime;
}
Vamos alterar essa função da posição não mais para que ela se mova de acordo com uma velocidade, mas para que ela se mova em passos iguais. Assim vamos garantir algumas coisas:
- O passo que a cobra vai dar não vai depender de cálculos físicos ou processamento de frames do computador;
- Vamos garantir aquelas bordas que mencionamos algumas vezes, já que ela vai andar sempre em passos iguais vai ter as brechas entre um espaço e outro.
Tudo que a gente precisa fazer é alterar esse trecho de movimento para:
public float stepOffset = 1f;
void OnTick()
{
// TO DO: perform action
transform.position += direction * stepOffset;
}
Detalhe, agora que nós temos uma variável do tipo pública nós vamos ter uma informação nova no editor da Unity. O que isso significa? Que vamos poder alterar o valor dessa variável sem precisar ficar voltando no código e compilando novamente os scripts. Isso pode ser chato de ficar repetindo e até um consumo de tempo se repetir algumas poucas 500 vezes...
Com isso, tudo que precisamos fazer para alterar o tamanho do passo da nossa cobra é mudar este valor. E como deixamos ele como float isso nos permite ainda fazer passos bem pequenos. Fique à vontade para mexer com este valor e encontrar um que seja do seu gosto.
Show demais. Agora vamos ajustar a questão dos colisores. Precisamos verificar 3 tipos de colisões diferentes. São elas:
- Colisão com paredes;
- Colisão com a fruta;
- Colisão com a cobra.
Todas estas colisões vão ser identificadas na cabeça da cobra. A parte que esta à frente do movimento, logo vamos colocar um colisor nela. Escolhemos o tipo spherecollider.
Vale ressaltar que este colisor não deve estar tocando no chão, se não pode nos atrapalhar nas verificações que iremos fazer. Marque também a opção de IsTrigger, pois este colisor não fará parte de interações físicas. Pronto, já ajustamos o tamanho do colisor, a posição e a física dele para que possa encaixar melhor no nosso modelo, representado pelo cubo. Lembre-se que este é apenas um placeholder, podemos modificar tanto o modelo como os valores do colisor para se adequarem melhor à cada caso.
Por padrão, os objetos que usamos para criar nossa cena já vem com colisores pré definidos neles e não iremos precisar inserir outros. Mas lembre-se que se você estiver usando modelos próprios precisará analisar quais colisores serão as melhores opções.
Por fim, para verificar colisões precisaremos adicionar um RigidBody no mesmo objeto que tem o script SnakeComponent já que ele quem vai verificar as colisções. O componente do RigidBody é um componente físico que permite verificações de colisão. Marque a opção de IsKinematic garantindo que os efeitos físicos no colisor não irão interferir no controle do modelo; basicamente só moveremos o objeto via script e animações. E também desmarque a opção UseGravity já que não iremos ter essa influência.
Vamos adicionar este trecho de código no script SnakeComponent e verificar se está ocorrendo como deveria:
void OnTriggerEnter(Collider other) {
Debug.Log("Colliding with " + other.transform.name);
}
A Unity traz duas funções de colisões. OnTriggerEnter e OnCollisionEnter. Basicamente podemos separar ambas em:
- OnTriggerEnter - usada quando verificamos colisões de checagem. Se dois colisores estão se tocando sem interações físicas.
- OnCollisionEnter - usada quando precisamos de informações da física dos objetos, como por exemplo: velocidade, ângulo de contato, ponto de contato, entre outros.
Você pode ler mais sobre isso na documentação da Unity, que inclusive é bem organizada e tem muito conteúdo para ser absorvido. Vamos testar nossa colisão agora.
Incrível :D tudo indo de acordo com o planejado sem mais erros absurdos e interações estranhas. Eu aproveitei para mudar a posição da fruta pois assim fica mais fácil testar sem precisar ficar movendo direções da cobra. E aqui encerra a primeira parte de hoje. Revise tudo que foi feito e lembre-se de tirar dúvidas no nosso grupo do whatsapp se houver alguma parte que complicou.
2. Adição de uma nova parte
Pra gente completar o tutorial de hoje vamos fazer somente a adição de uma nova parte da cobra. Pra isso a gente vai dar uma revisada lá naquela função Grow que criamos e deixamos um comentário para voltar nela depois.
void Grow()
{
// TODO
// Debug.Log("I'm working");
length += 1;
Debug.Log("Snake length " + length);
}
Havíamos deixado um comentário // TODO que significa "a fazer", basicamente dizendo que ainda temos trabalho a ser feito nessa função. Vamos começar criando um novo modelo 3D para representar nossa nova parte da cobra.
Criamos um cubo, nomeamos de "Snake Part", escalamos pra ficar agradável, criamos um novo material e arrastamos o material em cima do cubo. É isto. Vamos vivendo com placeholders temporariamente. Agora, vamos transformar esse cubo em um prefab. Basta arrastar ele para a pasta do projeto.
O prefab é um pré fabricado. Basicamente é um novo modelo que tem suas informações pré definidas. E o interessante deste novo modelo pré fabricado é que suas informações são compartilhadas entre todos os elementos deste prefab. Isso pode ser interessante porque assim no futuro, se a gente estiver usando ele em diversos lugares podemos simplesmente alterar seu modelo no prefab e então vai ser automaticamente atualizado em todos os cantos que usam ele.
Gente, vamos olhar pro código agora. Precisamos adicionar um novo trecho que vai nos permitir criar um objeto na cena que seja um clone do nosso prefab. Pra isso vamos adicionar uma referência para este objeto e chamar uma função que nos auxilia na criação desse elemento.
public GameObject snakePartPrefab;
void Grow()
{
// TODO
// Debug.Log("I'm working");
length += 1;
Debug.Log("Snake length " + length);
Instantiate(snakePartPrefab);
}
void OnTriggerEnter(Collider other)
{
Debug.Log("Colliding with " + other.transform.name);
Grow();
}
Nossa, eu até suei pra fazer esse trecho de código. Mas se a gente olhar com calma vai ver que nem é tão complicado. Nossa variável pública permite que a gente veja essa variável no editor e assim teremos liberdade para arrastar e soltar nosso prefab direto no editor. E agora quando a gente colidir com um objeto iremos chamar a função de Grow para crescer o tamanho da cobra. Podemos testar.
Show galera. Mas temos um problema agora, acontece que ao colidir com qualquer objeto, inclusive paredes, vai acabar gerando uma parte nova da cobra. Isso não é um comportamento esperado... Por isso vamos precisar implementar algumas condições para verificar com o que estamos colidindo. Para isso vamos aprender a mexer nas tags da Unity.
As tags são elementos particulares dos objetos que servem para identificar se pertencem a um grupo ou não. Podemos facilmente criar e manipular essas tags no canto superior esquerdo do inspector de cada elemento. Selecione a fruta e vamos adicionar uma nova tag para ela. Você precisa criar a tag e depois adicionar ao objeto.
[5-9]
Lembre-se que depois de criar, você precisa voltar lá no componente e anexar a tag recém-criada.
[5-10]
E agora no código de colisão, vamos verificar se o objeto que estamos colidindo tem a tag da fruta, e somente nesse caso vamos chamar a função de crescimento.
void OnTriggerEnter(Collider other) {
Debug.Log("Colliding with " + other.transform.name);
if (other.transform.CompareTag("Fruit")) {
Grow();
}
}
Agora podemos verificar que só crescemos quando encostamos na fruta.
Conclusão
Pessoal, encerramos mais uma parte deste tutorial. Iai, o que estão achando? Chamem a gente no grupo, comentem e compartilhem os avanços de vocês. Estamos ansiosos por ver o progresso de vocês. Próximo tutorial terá como foco a movimentação das novas partes da cobra, fiquem atentos pois vamos dar atenção à programação de uma funcionalidade introdutória para programadores que desejam avançar no mundo da programação.