Tutorial de como criar um movimento em grid na Unity, mostrando um personagem voxel pulando em blocos em uma câmera isométrica, no estilo Crossy Road.

Como Criar um Jogo no Estilo “Crossy Road” na Unity (Movimentação em Grid)

Crossy Road é um daqueles jogos geniais. É simples, viciante, e tem um visual icônico. Para quem está começando na Unity, tentar replicar aquele visual e, principalmente, aquela sensação de movimento, pode ser um pesadelo.

Se você tentar usar um Rigidbody ou um CharacterController padrão, o personagem vai se mover livremente. Mas em Crossy Road, o personagem “salta” de um ponto para o outro, como se estivesse num tabuleiro (ou grid).

Como diabos eles fazem isso?

A boa notícia: não é mágica. É uma combinação inteligente de três coisas: uma câmera específica, um script de movimento simples e um pequeno truque de “juice” para fazer o pulo parecer gostoso.

Vamos quebrar o código e a lógica para você criar o MVP dessa mecânica agora.


Passo 1: A Câmera “3D Falsa” (Ortográfica)

O primeiro segredo do visual do jogo é a câmera. Embora o jogo seja 3D, ele não usa a câmera em “Perspectiva” padrão.

  1. Crie um novo projeto 3D na Unity.
  2. Na sua Main Camera, vá até o Inspector.
  3. Encontre a propriedade Projection e mude de Perspective para Orthographic.
  4. Ajuste a Rotation da câmera para ter uma visão isométrica. Um bom ponto de partida é: X = 30, Y = 45, Z = 0.
  5. Use a propriedade Size para controlar o zoom (quanto menor o número, mais “perto” a câmera fica).

Pronto. Agora, qualquer objeto 3D que você colocar na cena terá aquele visual “achatado” e estilizado, sem distorção de perspectiva.


Passo 2: O Cérebro (O Script de Movimento em Grid)

Este é o coração da mecânica. Não vamos usar física. Vamos controlar a posição do jogador diretamente, pulando de um ponto a outro.

  1. Crie um Cube 3D (ou importe seu personagem) e coloque-o na posição (0, 0, 0). Vamos chamá-lo de “Jogador”.
  2. Crie um novo script C# chamado MoveGrid e adicione-o ao seu “Jogador”.
  3. Abra o script. A lógica é a seguinte:
    • Não queremos movimento contínuo (GetKey). Queremos uma ação única por aperto (GetKeyDown).
    • Quando o jogador apertar “W”, queremos que ele se mova exatamente 1 unidade para frente (Vector3.forward).
    • Quando apertar “A”, 1 unidade para a esquerda (Vector3.left), e assim por diante.

Nosso primeiro rascunho de código dentro do Update() poderia ser este:

// DENTRO DO UPDATE - VERSÃO RUIM (INSTANTÂNEA)
void Update()
{
    if (Input.GetKeyDown(KeyCode.W))
    {
        transform.position += Vector3.forward;
    }
    if (Input.GetKeyDown(KeyCode.A))
    {
        transform.position += Vector3.left;
    }
    // ... etc para S e D
}

Isso funciona. O personagem vai “teleportar” 1 unidade para frente. Mas não é “gostoso”. Não tem peso. Falta o “pulo”.


Passo 3: O “Juice” (O Pulo Suave com Coroutine e Lerp)

Para fazer o movimento parecer um “pulo”, o personagem precisa levar um curto período de tempo (ex: 0.2 segundos) para ir da Posição A para a Posição B.

A melhor forma de fazer isso é com uma Coroutine. Uma coroutine é uma função que pode ser pausada e continuada.

Vamos reescrever nosso script MoveGrid para usar essa técnica:

using System.Collections;
using UnityEngine;

public class MoveGrid : MonoBehaviour
{
    // O tempo que o pulo leva, em segundos
    public float moveDuration = 0.2f;

    // Para evitar que o jogador aperte o botão várias vezes enquanto já está pulando
    private bool canMove = true;

    void Update()
    {
        // Só checa por input se o jogador puder se mover
        if (canMove)
        {
            if (Input.GetKeyDown(KeyCode.W))
            {
                StartCoroutine(MovePlayer(Vector3.forward));
            }
            else if (Input.GetKeyDown(KeyCode.S))
            {
                StartCoroutine(MovePlayer(Vector3.back));
            }
            else if (Input.GetKeyDown(KeyCode.A))
            {
                StartCoroutine(MovePlayer(Vector3.left));
            }
            else if (Input.GetKeyDown(KeyCode.D))
            {
                StartCoroutine(MovePlayer(Vector3.right));
            }
        }
    }

    // A Coroutine mágica que move o jogador suavemente
    private IEnumerator MovePlayer(Vector3 direction)
    {
        // Bloqueia o movimento até que o pulo termine
        canMove = false;

        // Posição inicial
        Vector3 startPosition = transform.position;
        
        // Posição final (ex: posição inicial + 1 unidade para frente)
        Vector3 endPosition = startPosition + direction;

        float elapsedTime = 0f;

        // Loop que dura exatamente o tempo de 'moveDuration'
        while (elapsedTime < moveDuration)
        {
            // Lerp (Interpolação Linear) calcula a posição intermediária
            transform.position = Vector3.Lerp(startPosition, endPosition, elapsedTime / moveDuration);
            
            // Avança o tempo
            elapsedTime += Time.deltaTime;
            
            // Espera até o próximo frame
            yield return null;
        }

        // Garante que o jogador termine exatamente na posição final (corrige imprecisões)
        transform.position = endPosition;

        // Libera o movimento para o próximo pulo
        canMove = true;
    }
}

Para adicionar o “pulo” visual: Você pode adicionar um pequeno movimento no eixo Y (altura) dentro da coroutine. Uma forma simples é usar uma curva de animação (AnimationCurve) ou matemática (ex: Mathf.Sin) para fazer o transform.position.y subir e descer durante o moveDuration.


Conclusão: Você Deconstruiu a Mecânica

Pronto. Você acabou de criar o coração de Crossy Road.

Você não construiu o jogo inteiro (isso seria scope creep!), mas você construiu o MVP da mecânica principal. Você aprendeu:

  1. A usar uma câmera Ortográfica para um visual 3D estilizado.
  2. A usar GetKeyDown para um input que acontece uma vez por aperto.
  3. A usar uma Coroutine com Vector3.Lerp para criar um movimento suave e “gostoso” que não é instantâneo.

É assim que você deve abordar qualquer jogo que pareça complexo: quebre-o em partes menores, descubra qual é a mecânica central e construa um MVP funcional dela. O resto (geração de mundo, carros, pontuação) é só consequência.

Qual outra mecânica de jogo famoso você gostaria de ver desconstruída? Deixe nos comentários!

Compartilhe !