1. Introdução – O Que Vamos Construir?
Vamos criar um jogo de Quiz interativo usando Unity 6 e a linguagem C#. O quiz vai ter perguntas com imagens, um timer (contagem regressiva) para cada pergunta, pontuação, tela de Game Over e a possibilidade de reiniciar o jogo.
1.1 O que é um Quiz?
Um quiz é um jogo de perguntas e respostas. O jogador vê uma pergunta com alternativas e precisa escolher a resposta certa. Pense nos programas de TV como “Show do Milhão” ou nos quizzes que você faz em aplicativos no celular – o conceito é o mesmo!
1.2 O que vamos aprender?
- ScriptableObject – uma forma inteligente de guardar dados na Unity (como um banco de dados de perguntas)
- Canvas e UI – como criar telas com botões, textos e painéis
- Timer (contagem regressiva) – como criar um relógio que conta o tempo para responder
- Organização de código – separar responsabilidades em scripts diferentes
- Lógica de jogo – pontuação, aleatório, embaralhar alternativas e Game Over
1.3 Visão Geral do Projeto
Nosso quiz funcionará assim:
- O jogo carrega uma lista de perguntas de um ScriptableObject
- Cada pergunta aparece na tela com uma imagem ilustrativa e 4 alternativas embaralhadas
- Um timer de 15 segundos começa a contar – se o tempo acabar, pula para a próxima pergunta sem pontuar
- Se o jogador acertar, ganha 10 pontos
- Quando todas as perguntas acabarem, aparece a tela de Game Over com a pontuação final
- O jogador pode reiniciar o quiz
| 💡 Conceito: ScriptableObject
ScriptableObject é um tipo especial de classe da Unity que permite criar “contêineres de dados” que ficam salvos como arquivos no seu projeto. É como criar uma planilha do Excel dentro da Unity – você preenche os dados (perguntas, alternativas, imagem) e o seu código lê esses dados durante o jogo. A grande vantagem: você muda as perguntas sem precisar mexer no código! |
2. Preparando o Projeto na Unity
2.1 Criando o Projeto
| 1 | Abrir a Unity Hub e criar um projeto |
Abra a Unity Hub, clique em New Project, escolha o template Universal 2D Core e nomeie o projeto como “QuizGame”. Clique em Create Project.

2 |
Importar o TextMeshPro |
Quando o projeto abrir, vá em Window > TextMeshPro > Import TMP Essential Resources. Clique em Import. O TextMeshPro é a biblioteca que usamos para textos bonitos na Unity.
| ⚠️ Atenção!
Se aparecer um aviso pedindo para importar o TMP, clique em “Import TMP Essentials”. Sem isso, os textos não funcionarão corretamente. |
2.2 Organizando as Pastas
Organize seu projeto criando as seguintes pastas dentro de Assets. Para criar pastas, clique com o botão direito na janela Project e escolha Create > Folder:
- Scripts – onde ficarão todos os nossos códigos C#
- Data – onde ficarão os ScriptableObjects (nossas perguntas)
- Sprites – onde ficarão as imagens das perguntas
- Scenes – onde fica a cena do jogo (já existe por padrão)

3. Criando a Interface (Canvas e Painéis)
A interface do nosso quiz é feita com o sistema de UI (User Interface) da Unity. Toda interface fica dentro de um objeto chamado Canvas. Vamos criar o Canvas e seus painéis.
3.1 Criar o Canvas
| 1 | Criar o Canvas |
Na janela Hierarchy 🡪 botão direito do mouse 🡪 selecione UI 🡪 Canvas.
Ou no menu superior, clique em GameObject > UI > Canvas. Isso cria automaticamente um Canvas e um EventSystem na Hierarchy.
| 2 | Configurar o Canvas Scaler |
Selecione o Canvas na Hierarchy. No Inspector, encontre o componente Canvas Scaler e configure:
- UI Scale Mode: Scale With Screen Size
- Reference Resolution: 1920 x 1080
- Match: 0.5 (deslize o slider até o meio)
| 💡 Por que configurar o Canvas Scaler?
O Canvas Scaler faz com que a interface se adapte a diferentes tamanhos de tela. Se o jogador estiver num celular ou num monitor grande, os botões e textos vão manter o tamanho proporcional. Sem isso, a UI pode ficar gigante ou minúscula dependendo da resolução. O Match diz para a engine como ela deve calcular essa escala quando a tela do jogador tiver uma proporção diferente do seu 1920×1080 (que é a proporção 16:9, ou seja, mais retangular). Match 0.5 (Meio): É o ponto de equilíbrio. Ao deixar o slider no meio, você está dizendo para a engine fazer uma média e considerar tanto a largura quanto a altura de forma igual. |
3.2 Painel de Pergunta (painelPergunta)
| 1 | Criar o painel |
Clique com o botão direito no Canvas (na Hierarchy) e escolha UI > Panel. Renomeie para painelPergunta.

| 2 | Posicionar o painel |
Com o painelPergunta selecionado, no Inspector, no componente Rect Transform, configure para que ele fique na parte superior da tela. Você pode ajustar o Anchor para top-stretch e definir uma altura de aproximadamente 350 pixels.

| 3 | Adicionar o texto da pergunta |
Clique com o botão direito no painelPergunta e escolha UI > Text – TextMeshPro. Renomeie para txtPergunta. Configure o tamanho da fonte para 36 e negrito (Bold) e deixe o texto centralizado. Ajuste o Rect Transform para ocupar a parte superior do painel.

Ajuste a posição e tamanho da caixa de texto para as seguintes configurações, ou deixe sua preferência: Pos X = 200 ; Pos Y = 0 ; width = 1500 (largura)

A “caixa” do texto cresce e encolhe conforme você digita
Essa é a opção ideal se você quer que o tamanho do objeto (o Rect Transform) acompanhe a quantidade de texto, muito útil para balões de diálogo ou botões que mudam de tamanho.
- Selecione o seu objeto de texto (TextMeshPro) na aba Hierarchy.
- No Inspector, clique no botão Add Component lá embaixo.
- Digite e adicione o componente chamado Content Size Fitter.
- Neste novo componente, você verá duas opções principais: Horizontal Fit (ajuste na largura) e Vertical Fit (ajuste na altura).
- Mude essas opções conforme imagem abaixo:

O que acontece: Agora, se o texto tiver apenas uma palavra, a caixa será pequena. Se for um parágrafo inteiro, a caixa do Rect Transform vai se expandir automaticamente para abraçar todo o conteúdo.
| 4 | Adicionar a imagem da pergunta |
Clique com o botão direito no painelPergunta e escolha UI > Image. Renomeie para imgPergunta. Posicione ao lado esquedo do texto, com um tamanho de aproximadamente 300×300 pixels. Esta imagem irá mostrar uma figura relacionada à pergunta atual. Ajuste as posições e tamanho conforme a figura abaixo:

3.3 Painel de Alternativas (painelAlternativas)
| 1 | Criar o painel |
Clique com o botão direito no Canvas e escolha UI > Panel. Renomeie para painelAlternativas. Posicione abaixo do painelPergunta. Configure o tamanho conforme imagem abaixo:

| 2 | Criar os 4 botões |
Dentro do painelAlternativas, crie 4 botões: clique com o botão direito no painelAlternativas e escolha UI > Button – TextMeshPro. Repita 4 vezes e renomeie para: btn0, btn1, btn2 e btn3.

| 3 | Organizar os botões |
Para organizar os botões de forma automática, adicione um componente Vertical Layout Group ao painelAlternativas. No Inspector, clique em Add Component, procure por “Vertical Layout Group” e configure:
- Spacing: 10 (espaço entre cada botão)
- Child Alignment: Middle Center
- Control Child Size: marque Width e Height

3.4 Painel de Informações (painelInfo)
| 1 | Criar o painel |
Crie mais um painel no Canvas e renomeie para painelInfo. Posicione do lado direito (como uma barra de informações). Segue imagem com as configurações:

| 2 | Adicionar texto de pontuação |
Dentro do painelInfo, crie um UI > Text – TextMeshPro e renomeie para txtPontos. Configure o texto inicial como “Pontos: 0”.

| 3 | Adicionar texto do timer |
Crie outro UI > Text – TextMeshPro dentro do painelInfo e renomeie para txtTimer. Configure o texto inicial como “Tempo: 15”. Este texto irá mostrar a contagem regressiva. Mude a Pos Y : 310

3.5 Painel de Game Over (painelFim)
| 1 | Criar o painel |
Crie mais um painel no Canvas e renomeie para painelFim. Configure para cobrir toda a tela (stretch em todas as direções). Defina a cor de fundo como escura com alta opacidade (ex: RGBA 0, 0, 0, 220).

| 2 | Adicionar texto de pontuação final |
Dentro do painelFim, crie um Text – TextMeshPro e renomeie para txtPontosFinal. Centralize e aumente a fonte para 40 e negrito.
| 3 | Adicionar botão de reiniciar |
Crie um Button – TextMeshPro dentro do painelFim e renomeie para btnReiniciar. Mude o texto do botão para “Jogar Novamente” (Na Hierarchy, expanda o btnReiniciar) .

| 4 | Desativar o painel |
IMPORTANTE: Desmarque o checkbox ao lado do nome “painelFim” no Inspector (isso desativa o painel). Ele só vai aparecer quando o quiz acabar!

| 🎮 Resumo da Hierarquia do Canvas
|
4. Criando os Scripts
Agora vamos criar os scripts C# do nosso quiz. Vamos separar o código em scripts diferentes, cada um com uma responsabilidade. Isso é uma boa prática de programação chamada Separação de Responsabilidades.
| 💡 Por que separar em vários scripts?
Imagine que você tem um armário com uma gaveta só. Tudo fica misturado: meias, camisetas, calças. Agora imagine um armário com várias gavetas organizadas. Cada script é como uma gaveta: guarda só o que é da sua responsabilidade. Isso facilita encontrar e consertar problemas no código! |
Nosso projeto terá 4 scripts:
- Perguntas.cs – define a estrutura de cada pergunta (enunciado, alternativas, resposta correta, imagem)
- Questionarios.cs – o ScriptableObject que funciona como um “banco de dados” de perguntas
- GerenciadorPerguntas.cs – responsável por carregar e embaralhar as perguntas
- MecanicasQuiz.cs – responsável pelas regras do jogo: pontuação, timer, Game Over e reiniciar

4.1 Script: Perguntas.cs (Estrutura da Pergunta)
Este script define como é uma pergunta. É como criar um “molde” que diz: toda pergunta tem um enunciado, alternativas, uma resposta correta e agora também uma imagem.
Criando o script:
- Na pasta Scripts, clique com o botão direito > Create > MonoBehaviour Script
- Nomeie como “Perguntas” (sem espaços e com P maiúsculo)
- Abra o script no editor de código e substitua todo o conteúdo pelo código abaixo:

Entendendo o código linha por linha:
| using UnityEngine; | Importa a biblioteca da Unity para que possamos usar tipos como Sprite. |
| [System.Serializable] | Este atributo diz para a Unity: “mostre os campos desta classe no Inspector”. Sem isso, não conseguiríamos preencher os dados no editor. |
| public class Perguntas | Cria a classe chamada Perguntas. Uma classe é como um “molde” ou “formulário”. |
| public string enunciado; | Campo de texto que armazena o enunciado (a pergunta em si). |
| public string[] alternativas; | Um array (lista fixa) de textos. Cada posição guarda uma alternativa. |
| public int respostaCorreta; | Um número inteiro que indica qual alternativa é a correta. Lembre-se: arrays começam no índice 0! |
| public Sprite imagemPergunta; | NOVIDADE! Um Sprite é uma imagem 2D na Unity. Este campo permite associar uma imagem a cada pergunta. |
| 🖼️ Como funciona o Sprite?
Sprite é o tipo de imagem que a Unity usa para jogos 2D e UI. Para usar uma imagem como Sprite, você precisa importar a imagem para a pasta Imagens do projeto e no Inspector, mudar o Texture Type para “Sprite (2D and UI)”. |
4.2 Script: Questionarios.cs (Banco de Dados de Perguntas)
Este script cria o ScriptableObject. Pense nele como uma “planilha” que a Unity entende. Você cria vários arquivos deste tipo, cada um com um conjunto diferente de perguntas.
Criando o script:
- Na pasta Scripts, crie um Script chamado “Questionarios”
- Substitua o conteúdo pelo código:

Entendendo o código:
| [CreateAssetMenu(…)] | Este atributo cria uma opção no menu da Unity (botão direito > Create > Quiz > Questionario). É assim que vamos criar nossos “bancos de perguntas” sem programar! |
| fileName = “NovoQuestionario” | O nome padrão do arquivo quando você criar um novo. |
| menuName = “Quiz/Questionario” | O caminho no menu Create. O “/” cria uma subpasta (Quiz) para organizar. |
| : ScriptableObject | A classe herda de ScriptableObject. Isso significa que ela PODE ser salva como um arquivo .asset na Unity. |
| public string nomeQuestionario; | NOVO: campo de texto para dar um nome ao questionário (será útil na Apostila 2 para o menu de temas). |
| public Perguntas[] listaPerguntas; | Um array do tipo Perguntas. Cada elemento deste array é uma pergunta completa (enunciado + alternativas + resposta + imagem). |
4.3 Criando um Questionário (ScriptableObject)
Agora que temos os dois primeiros scripts salvos, vamos criar nosso primeiro questionário:
| 1 | Preparar as imagens |
Importe imagens para a pasta Assets/Imagens. Para cada imagem, selecione-a no Inspector e mude o Texture Type para “Sprite (2D and UI)” e clique em Apply.
| 2 | Criar o ScriptableObject |
Na pasta Assets/Data, clique com o botão direito > Create > Quiz > Questionario. Renomeie o arquivo para “PerguntasGerais” (ou o nome que preferir).


| 3 | Preencher as perguntas |
Selecione o arquivo “PerguntasGerais” e no Inspector:
- Nome Questionario: “Conhecimentos Gerais”
- Lista Perguntas – Size: coloque o número de perguntas (ex: 5)
Para cada pergunta (Element 0, Element 1, etc.), preencha:
- Enunciado: o texto da pergunta
- Alternativas – Size: 4, e preencha as 4 alternativas
- Resposta Correta: o índice da resposta certa (0 = primeira, 1 = segunda, 2 = terceira, 3 = quarta)
- Imagem Pergunta: arraste uma imagem da pasta Imagens para este campo
| ✍️ Exemplo de Pergunta
Enunciado: “Qual é o maior planeta do Sistema Solar?” | Alternativas: [0] Júpiter, [1] Saturno, [2] Terra, [3] Marte | Resposta Correta: 0 | Imagem: uma foto de Júpiter |
4.4 Script: GerenciadorPerguntas.cs (Carregar e Embaralhar Perguntas)
Este script é responsável por: carregar as perguntas do ScriptableObject, embaralhar as alternativas, mostrar a pergunta na tela e verificar se o jogador acertou. Ele cuida apenas de PERGUNTAS – nada de pontuação ou timer. Obs.: Irá dar um erro na linha 22, MecanicasQuiz, pois ainda iremos fazer esse script.

Entendendo as partes principais:
[Header(“…”)]: Cria uma separação visual no Inspector da Unity. Ajuda a organizar as variáveis em categorias.
public Image imgPergunta: Referência para o componente Image da UI. É onde a imagem da pergunta será exibida.
GetComponent<MecanicasQuiz>(): Busca o outro script (MecanicasQuiz) que está no MESMO GameObject. Por isso ambos os scripts devem estar no mesmo objeto!
new List<Perguntas>(…): Cria uma CÓPIA da lista de perguntas. Assim, quando removemos perguntas já exibidas, o ScriptableObject original não é alterado.
Random.Range(0, listaPerguntas.Count): Sorteia um número aleatório entre 0 e o total de perguntas restantes. Isso faz as perguntas aparecerem em ordem diferente cada vez!
RemoveAt(indice): Remove a pergunta da lista após exibi-la, garantindo que ela não se repita.
imgPergunta.gameObject.SetActive(false): Se a pergunta não tem imagem, escondemos o componente de imagem. Se tem, mostramos e atualizamos o sprite.
Fisher-Yates Shuffle: O algoritmo que embaralha as alternativas. Funciona trocando cada elemento com outro em posição aleatória, como embaralhar cartas de um baralho.
onClick.RemoveAllListeners(): Remove os eventos antigos do botão. Sem isso, ao carregar uma nova pergunta, o botão acumularia vários eventos e causaria bugs!
onClick.AddListener(() => …): Adiciona um novo evento ao botão. O “() =>” é uma expressão lambda – uma forma curta de criar uma função anônima.
4.5 Script: MecanicasQuiz.cs (Regras, Timer e Pontuação)
Este script cuida de tudo relacionado às regras do jogo: a pontuação, o timer (contagem regressiva), o Game Over e o reiniciar. Ele NÃO sabe nada sobre perguntas – só recebe se o jogador acertou ou errou.


Entendendo as partes principais:
Time.deltaTime: Retorna o tempo (em segundos) que passou desde o último frame. Subtraindo esse valor de tempoRestante, a contagem regressiva funciona independente da velocidade do computador.
Mathf.CeilToInt(): Arredonda um número decimal para cima e converte para inteiro. Exemplo: 14.3 vira 15. Assim o timer mostra “15” até realmente passar 1 segundo completo.
timerAtivo (bool): Funciona como um interruptor. Quando é true, o timer conta. Quando é false, o timer para. Isso evita que o tempo continue contando durante o Game Over.
Color.red / Color.white: Cores prontas da Unity. Quando faltam 5 segundos, o texto do timer fica vermelho para criar urgência no jogador!
tempoMaximo = 15f: O “f” no final indica que é um número float (decimal). O valor 15 pode ser alterado no Inspector sem mexer no código.
public void Responder(bool acertou): Recebe true se o jogador acertou, false se errou. Para o timer imediatamente e só soma pontos se acertou.
| 🔗 Como os scripts se comunicam?
GerenciadorPerguntas e MecanicasQuiz ficam no MESMO GameObject. Cada um usa GetComponent para encontrar o outro. Quando o jogador clica num botão, GerenciadorPerguntas chama mecanicas.Responder(). Quando a resposta é processada, MecanicasQuiz chama gerenciador.CarregarPergunta(). Eles trabalham juntos como uma equipe! |
5. Conectando Tudo na Unity
Agora que temos todos os scripts criados, precisamos conectar tudo na Unity. Esta é a parte mais importante – se alguma referência ficar faltando, o jogo não funciona!
5.1 Criar o GameObject do Quiz
| 1 | Criar um GameObject vazio |
Na janela Hierarchy – Botão direito 🡪 Create Empty
Ou no menu superior: GameObject > Create Empty. Renomeie para “GerenciadorQuiz”.

| 2 | Adicionar os dois scripts |
Com o GerenciadorQuiz selecionado, no Inspector, clique em Add Component e adicione:
- GerenciadorPerguntas
- MecanicasQuiz

| ⚠️ Importante!
Os dois scripts DEVEM estar no MESMO GameObject! Eles usam GetComponent para se encontrar. Se estiverem em objetos diferentes, o jogo vai dar erro NullReferenceException. |
5.2 Conectar as Referências do GerenciadorPerguntas
Com o GerenciadorQuiz selecionado, encontre o componente GerenciadorPerguntas no Inspector e arraste:
| Campo no Inspector | O que arrastar |
| Txt Pergunta | Arraste o txtPergunta (do painelPergunta) para este campo |
| Img Pergunta | Arraste o imgPergunta (do painelPergunta) para este campo |
| Btn Alternativas | Defina Size como 4, depois arraste btn0, btn1, btn2 e btn3 |
| Questionario Atual | Arraste o ScriptableObject “PerguntasGerais” da pasta Data |
5.3 Conectar as Referências do MecanicasQuiz
Ainda no GerenciadorQuiz, encontre o componente MecanicasQuiz e arraste:
| Campo no Inspector | O que arrastar / configurar |
| Txt Pontos | Arraste o txtPontos (do painelInfo) |
| Txt Timer | Arraste o txtTimer (do painelInfo) |
| Painel Fim | Arraste o painelFim (da Hierarchy) |
| Txt Pontos Final | Arraste o txtPontosFinal (dentro do painelFim) |
| Tempo Maximo | Deixe 15 (ou mude para o tempo que desejar) |
5.4 Configurar o Botão de Reiniciar
| 1 | Selecionar o btnReiniciar |
Na Hierarchy, dentro do painelFim, clique no btnReiniciar.
| 2 | Configurar o evento OnClick |
No Inspector, encontre o componente Button e na seção On Click():
- Clique no “+” para adicionar um novo evento
- Arraste o GameObject “GerenciadorQuiz” para o campo None (Object)
- No dropdown, selecione MecanicasQuiz > Reiniciar
6. Testando o Quiz
6.1 Checklist antes de testar
Antes de clicar em Play, verifique:
- ☐ Os scripts Perguntas.cs e Questionarios.cs estão na pasta Scripts sem erros no Console
- ☐ O ScriptableObject foi criado na pasta Data com pelo menos 3 perguntas preenchidas
- ☐ As imagens estão importadas e configuradas como Sprite (2D and UI)
- ☐ O Canvas tem os 4 painéis: painelPergunta, painelAlternativas, painelInfo e painelFim
- ☐ O painelFim está DESATIVADO (checkbox desmarcado)
- ☐ O GerenciadorQuiz tem os dois scripts: GerenciadorPerguntas e MecanicasQuiz
- ☐ Todas as referências estão arrastadas corretamente no Inspector
- ☐ O botão btnReiniciar está configurado para chamar MecanicasQuiz.Reiniciar()
6.2 Erros comuns e soluções
| NullReferenceException | Alguma referência não foi arrastada no Inspector. Verifique se todos os campos têm um objeto atribuído. |
| O timer não aparece | Verifique se o txtTimer foi arrastado para o campo correto no MecanicasQuiz. |
| A imagem não aparece | Verifique se a imagem foi importada como Sprite e arrastada no campo imagemPergunta do ScriptableObject. |
| Alternativas não mudam | Verifique se os 4 botões foram adicionados ao array btnAlternativas (Size = 4). |
| Botão reiniciar não funciona | Verifique se o evento OnClick do botão está configurado para MecanicasQuiz.Reiniciar(). |
| O quiz reinicia sozinho | Verifique se a cena está adicionada em File > Build Settings > Scenes In Build. |
7. Resumo e Diagrama de Comunicação
Vamos recapitular tudo o que fizemos e como os scripts se comunicam:
7.1 Arquivos do Projeto
| Arquivo | Tipo | Responsabilidade |
| Perguntas.cs | Classe serializável | Define a estrutura: enunciado, alternativas, resposta correta e imagem |
| Questionarios.cs | ScriptableObject | Contêiner de dados – armazena um array de Perguntas |
| GerenciadorPerguntas.cs | MonoBehaviour | Carrega perguntas, embaralha alternativas, mostra na UI |
| MecanicasQuiz.cs | MonoBehaviour | Pontuação, timer, Game Over, reiniciar |
7.2 Fluxo de Comunicação entre os Scripts
O diagrama abaixo mostra como cada script se comunica:

Canvas > painelPergunta (txtPergunta + imgPergunta) | painelAlternativas (btn0, btn1, btn2, btn3) | painelInfo (txtPontos + txtTimer) | painelFim (txtPontosFinal + btnReiniciar). O painelFim começa desativado.

Deixe um comentário