Voltar para o Blog
Quest Log

Unity 2D Tutorial: Como Fazer um Jogo 2D na Unity

Pequeno personagem 2D no chão desviando de blocos que caem do céu num cenário de cores chapadas

Unity 2D tutorial com projeto fechado: jogo de desviar de obstáculos com sprites, Rigidbody2D, spawner, game over e reinício, na ordem certa, com C# do Unity 6.

Ferramenta:UnityC#

Unity 2D Tutorial: Como Fazer um Jogo 2D na Unity

Neste unity 2d tutorial você monta um jogo 2D completo de uma tela: o jogador anda de um lado para o outro no chão, blocos caem do céu cada vez mais rápido, encostou é game over e a tecla R reinicia. São quatro scripts curtos em C# do Unity 6, Rigidbody2D, colisão por trigger, spawner, pontuação e reinício de cena.

O foco não é só o código. É a ordem de montagem. A maioria dos iniciantes trava no meio do primeiro jogo 2D porque começa pelo menu, pela arte ou pelo sistema de pontos, e só depois descobre que o movimento não funciona. Aqui cada etapa termina com algo que você testa no Play antes de passar para a próxima.

O jogo 2D que vamos montar

Regras:

  • O jogador fica no chão e só anda na horizontal (A/D ou setas).
  • Blocos aparecem numa altura fixa, em posição horizontal aleatória, e caem.
  • A velocidade de queda aumenta com o tempo.
  • A pontuação é o tempo sobrevivido em segundos.
  • Encostou num bloco: o jogo congela, aparece "Game Over" e R reinicia.

Escolhi um jogo de desviar e não um de plataforma de propósito. Plataforma exige pulo, ground check e ajuste fino de gravidade, e isso afoga o primeiro projeto. Desviar ensina os mesmos fundamentos (física, colisão, instanciar objetos, estado de jogo) com metade das armadilhas. Se você quer outras ideias desse tamanho, a lista de ideias de jogos simples para iniciantes tem várias.

A ordem de montagem que vamos seguir:

  1. Projeto e cena.
  2. Jogador que anda e não sai da tela.
  3. Um obstáculo que cai.
  4. Spawner que cria vários.
  5. Colisão e game over.
  6. Pontuação e reinício.

Criar o projeto Universal 2D

No Unity Hub, vá em Projects > New project, confira que a versão é a Unity 6.3 LTS e escolha o template Universal 2D. Ele vem com a URP configurada com o renderizador 2D e com a câmera em modo ortográfico, que é o que um jogo 2D precisa. Nomeie como Desvia e crie.

Com o projeto aberto, crie no Project as pastas Scripts, Sprites e Prefabs dentro de Assets. Parece burocracia, mas com quatro scripts e um prefab você já agradece.

Selecione a Main Camera e confira no Inspector: Projection em Orthographic e Size em 5. Com size 5, a câmera mostra 10 unidades de altura (de -5 a 5 no eixo Y). Em tela 16:9, isso dá por volta de 17,8 unidades de largura, então o X visível vai de cerca de -8,9 a 8,9. Esses números guiam onde colocar paredes e spawner.

Importar sprites e montar a cena

Você pode usar formas prontas ou arte sua.

Com formas prontas: na Hierarchy, botão direito, 2D Object > Sprites > Square. Serve para jogador, chão e obstáculos, mudando a cor no Sprite Renderer.

Com arte sua: arraste os PNGs para a pasta Sprites. No projeto 2D eles já entram com Texture Type em Sprite (2D and UI). Se for pixel art, selecione o arquivo e ajuste no Inspector: Pixels Per Unit igual ao tamanho do tile (ex.: 16 para sprites de 16x16), Filter Mode em Point (no filter) e Compression em None. Clique em Apply. Sem isso, pixel art fica borrada.

Monte a cena:

  1. Jogador: um Square na posição (0, -4, 0). Renomeie para Jogador.
  2. Paredes invisíveis: dois objetos vazios (Create Empty) chamados ParedeEsquerda em (-9.5, 0, 0) e ParedeDireita em (9.5, 0, 0). Em cada um, adicione um Box Collider 2D com Size (1, 12). Sem Sprite Renderer, elas não aparecem, mas a física enxerga.
  3. Obstáculo: um Square vermelho em (0, 6, 0), escala (0.8, 0.8, 1). Renomeie para Obstaculo. Vamos transformá-lo em prefab daqui a pouco.

Script do jogador com Rigidbody2D e Input System

No Jogador, adicione Rigidbody 2D e Box Collider 2D. No Rigidbody 2D:

  • Body Type: Dynamic (a física resolve a batida nas paredes).
  • Gravity Scale: 0 (ele não cai, fica no chão por definição).
  • Constraints: marque Freeze Position Y e Freeze Rotation Z.

Crie o script em Create > Scripting > MonoBehaviour Script. Arquivo JogadorDesvio.cs:

using UnityEngine;
using UnityEngine.InputSystem;

public class JogadorDesvio : MonoBehaviour
{
    [SerializeField] private Rigidbody2D rb;
    [SerializeField] private GerenciadorDeJogo gerenciador;
    [SerializeField] private float velocidade = 8f;

    private InputAction acaoMover;
    private float direcaoX;

    private void Awake()
    {
        acaoMover = InputSystem.actions.FindAction("Move");
    }

    private void Update()
    {
        direcaoX = acaoMover.ReadValue<Vector2>().x;
    }

    private void FixedUpdate()
    {
        rb.linearVelocity = new Vector2(direcaoX * velocidade, 0f);
    }

    private void OnTriggerEnter2D(Collider2D outro)
    {
        if (outro.CompareTag("Obstaculo"))
        {
            gerenciador.FimDeJogo();
        }
    }
}

Por que assim:

  • A ação Move vem pronta no asset InputSystem_Actions dos projetos novos da Unity 6. Ela devolve um Vector2; usamos só o x.
  • Input é lido no Update, física é aplicada no FixedUpdate. Misturar os dois causa movimento irregular.
  • linearVelocity é a propriedade de velocidade do Rigidbody2D na Unity 6. Código de tutorial antigo com velocity gera aviso de API obsoleta.
  • Como o corpo é Dynamic, as paredes invisíveis seguram o jogador sem nenhum Mathf.Clamp.

O script ainda não compila porque GerenciadorDeJogo não existe. Tudo bem: crie os outros scripts e o erro some. Se quiser se aprofundar em aceleração, atrito e pulo, o post de movimento de personagem 2D na Unity vai além do básico.

Obstáculos com spawner e colisão

O obstáculo

No objeto Obstaculo:

  1. Adicione Box Collider 2D e marque Is Trigger.
  2. Adicione Rigidbody 2D com Body Type em Kinematic. Kinematic se move pela velocidade que você define, sem gravidade e sem ser empurrado.
  3. No topo do Inspector, Tag > Add Tag, crie Obstaculo e aplique.

Arquivo Obstaculo.cs:

using UnityEngine;

public class Obstaculo : MonoBehaviour
{
    [SerializeField] private Rigidbody2D rb;
    [SerializeField] private float velocidadeQueda = 4f;
    [SerializeField] private float limiteInferiorY = -7f;

    public void DefinirVelocidade(float novaVelocidade)
    {
        velocidadeQueda = novaVelocidade;
    }

    private void Start()
    {
        rb.linearVelocity = Vector2.down * velocidadeQueda;
    }

    private void Update()
    {
        if (transform.position.y < limiteInferiorY)
        {
            Destroy(gameObject);
        }
    }
}

Anexe ao obstáculo, arraste o Rigidbody 2D para o campo Rb e aperte Play: o bloco cai e some ao sair da tela. Funcionou? Arraste o Obstaculo da Hierarchy para a pasta Prefabs e apague o da cena.

O spawner

Crie um objeto vazio Spawner em (0, 6, 0). Arquivo Spawner.cs:

using UnityEngine;

public class Spawner : MonoBehaviour
{
    [SerializeField] private Obstaculo prefabObstaculo;
    [SerializeField] private float intervalo = 0.8f;
    [SerializeField] private float metadeLargura = 8f;
    [SerializeField] private float velocidadeInicial = 4f;
    [SerializeField] private float aumentoPorSegundo = 0.15f;

    private float cronometro;
    private float tempoDeJogo;

    private void Update()
    {
        tempoDeJogo += Time.deltaTime;
        cronometro += Time.deltaTime;

        if (cronometro < intervalo)
        {
            return;
        }

        cronometro = 0f;
        float x = Random.Range(-metadeLargura, metadeLargura);
        Vector3 posicao = new Vector3(x, transform.position.y, 0f);
        Obstaculo novo = Instantiate(prefabObstaculo, posicao, Quaternion.identity);
        novo.DefinirVelocidade(velocidadeInicial + tempoDeJogo * aumentoPorSegundo);
    }
}

Arraste o prefab para o campo Prefab Obstaculo. Como DefinirVelocidade é chamado logo depois do Instantiate e o Start do obstáculo só roda depois, a velocidade nova já vale na primeira queda. A dificuldade sobe sozinha: a cada segundo, os blocos caem 0,15 unidade por segundo mais rápido.

Game over, pontuação e reinício da cena

Crie a interface:

  1. Hierarchy, botão direito, menu UI (Canvas), item de texto do TextMeshPro. Aceite Import TMP Essentials na primeira vez. Renomeie para TextoPontos e ancore no topo.
  2. Crie um Panel no mesmo Canvas, renomeie para PainelGameOver e coloque dentro dele um texto "Game Over. Aperte R".

Crie um objeto vazio Gerenciador. Arquivo GerenciadorDeJogo.cs:

using TMPro;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.SceneManagement;

public class GerenciadorDeJogo : MonoBehaviour
{
    [SerializeField] private TMP_Text textoPontos;
    [SerializeField] private GameObject painelGameOver;

    private float pontos;
    private bool acabou;

    private void Start()
    {
        Time.timeScale = 1f;
        painelGameOver.SetActive(false);
    }

    private void Update()
    {
        if (acabou)
        {
            Keyboard teclado = Keyboard.current;
            if (teclado != null && teclado.rKey.wasPressedThisFrame)
            {
                SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
            }
            return;
        }

        pontos += Time.deltaTime;
        textoPontos.text = Mathf.FloorToInt(pontos).ToString();
    }

    public void FimDeJogo()
    {
        if (acabou)
        {
            return;
        }

        acabou = true;
        Time.timeScale = 0f;
        painelGameOver.SetActive(true);
    }
}

Ligue as referências no Inspector: texto e painel no Gerenciador; Gerenciador no campo do Jogador.

Dois detalhes que fazem o reinício funcionar:

  • Time.timeScale = 0f congela física e tudo que usa Time.deltaTime. O Update continua rodando, por isso a leitura da tecla R funciona com o jogo parado. O Start volta o valor para 1 quando a cena recarrega.
  • SceneManager.LoadScene com índice só funciona se a cena estiver na lista de cenas do build. Abra File > Build Profiles, selecione o perfil ativo, abra a Scene List e clique em Add Open Scenes.

Pronto: aperte Play e jogue. Você fechou um jogo 2D com começo, meio, fim e recomeço.

Um jogo de uma tela com quatro scripts é administrável. O salto difícil vem quando o projeto pede personagem animado, várias fases, menu, save, som e câmera, tudo conversando sem virar um emaranhado. Organizar isso numa estrutura que cresce sem quebrar é a parte que quase ninguém aprende sozinho em vídeo solto.

Curso de Unity
Quer fazer seu primeiro jogo na Unity?

No curso de Unity 6 da CursoGame.Dev você vai do zero ao primeiro jogo, com um desafio prático em cada level e suporte individual no WhatsApp quando travar.

Conhecer o curso de Unity
Suporte no WhatsAppAcesso vitalícioGarantia de 7 dias

Erros comuns no primeiro jogo 2D na Unity

O jogador atravessa a parede: a parede não tem collider, ou o Rigidbody 2D do jogador está em Kinematic. Kinematic não é parado por colisores estáticos.

O obstáculo não cai: faltou arrastar o Rigidbody 2D para o campo Rb do script, ou o Body Type ficou Static.

Encosta no bloco e nada acontece: confira três coisas. A tag do prefab é Obstaculo (com a mesma grafia do código)? O collider do obstáculo está com Is Trigger? O jogador tem Rigidbody 2D? Trigger 2D só dispara se pelo menos um dos dois objetos tiver Rigidbody 2D.

R não reinicia: a cena não está na Scene List do Build Profile. O Console mostra um erro dizendo que a cena não pode ser carregada.

O jogo reinicia congelado: faltou o Time.timeScale = 1f no Start.

Blocos se acumulam abaixo da tela: o limiteInferiorY está abaixo do que eles alcançam, ou o script não está no prefab. Veja na Hierarchy durante o Play se os clones somem.

Sprites borrados: arte em pixel com Filter Mode em Bilinear. Troque para Point (no filter).

Próximo passo depois deste unity 2d tutorial

Agora melhore o mesmo jogo antes de começar outro. Cada item ensina um assunto novo sem perder o que você já tem:

  1. Melhor pontuação salva com PlayerPrefs.
  2. Tela inicial com botão Jogar, numa segunda cena.
  3. Som ao desviar por pouco e no game over.
  4. Partículas quando o jogador morre.
  5. Arte no lugar dos quadrados, com animação de corrida.

Se ainda está pesando se a Unity é a melhor ferramenta para o seu jogo 2D, o comparativo de melhor engine para jogos 2D põe Unity, Godot e outras lado a lado para esse tipo de projeto.

Perguntas frequentes

Qual template escolher para fazer jogo 2D na Unity?

Use o Universal 2D no Unity Hub. Ele cria um projeto vazio com a URP e o renderizador 2D já configurados, câmera ortográfica e importação de imagens como Sprite. É o ponto de partida recomendado para jogo 2D na Unity 6.

Preciso saber desenhar para fazer um jogo 2D na Unity?

Não para começar. A Unity cria formas simples (quadrado, círculo, triângulo) direto pelo menu 2D Object, e dá para fazer o jogo inteiro com elas. Arte entra depois, quando a mecânica já está divertida.

Por que meu jogo 2D na Unity não reinicia com SceneManager.LoadScene?

Quase sempre a cena não está na Scene List do Build Profile ativo, ou o Time.timeScale ficou em zero depois do game over. Adicione a cena em File > Build Profiles > Scene List e volte o timeScale para 1 no Start.

Rigidbody2D Dynamic ou Kinematic para o jogador?

Dynamic quando você quer que a física resolva colisões com paredes e chão, como neste tutorial. Kinematic quando você mesmo controla toda a posição por código e a física só serve para detectar contato.