Godot do Zero: Polimento do primeiro jogo 2D e empacotamento do build

Capítulo 17

Tempo estimado de leitura: 10 minutos

+ Exercício

Polimento: o que muda entre “funciona” e “parece pronto”

Polimento é a camada de feedback e consistência que ajuda o jogador a entender o que aconteceu (acertou, tomou dano, coletou algo, mudou de tela) e reduz fricções (transições suaves, dificuldade ajustável, janela/ícone corretos). Nesta etapa, você vai adicionar efeitos simples e parametrizar valores para ajustar o jogo sem “caçar números” em vários scripts.

Partículas simples (impacto, poeira, coleta)

Conceito

Partículas são efeitos visuais leves e rápidos (poeira ao correr/pular, faíscas ao acertar, brilho ao coletar). Em Godot 4, o mais comum é usar GPUParticles2D (mais eficiente) ou CPUParticles2D (mais compatível em alguns casos). A ideia é: criar um emissor configurado, deixar Emitting desligado por padrão e disparar quando um evento acontece.

Passo a passo: poeira ao aterrissar

  • Na cena do jogador, adicione um nó GPUParticles2D como filho (ex.: LandingDust).
  • No Inspector, configure:
    • One Shot = ligado
    • Emitting = desligado
    • Amount = 12–24
    • Lifetime = 0.25–0.5
    • Process Material = crie um ParticleProcessMaterial e ajuste Initial Velocity, Gravity e Scale
  • Posicione o emissor próximo aos pés do personagem.
  • Dispare ao detectar transição “no ar” → “no chão”. Se você já tem uma lógica de is_on_floor(), basta guardar o estado anterior.
extends CharacterBody2D

@onready var landing_dust: GPUParticles2D = $LandingDust
var was_on_floor := false

func _physics_process(delta: float) -> void:
	# ... seu movimento já existente ...
	var on_floor := is_on_floor()
	if on_floor and not was_on_floor:
		landing_dust.restart()
		landing_dust.emitting = true
	was_on_floor = on_floor

Dica: para efeitos de impacto (hit), use outro emissor com cor/velocidade diferentes e dispare na posição do contato (ex.: posição do inimigo ou do jogador).

Telas de transição (fade in/out) entre cenas e estados

Conceito

Transições evitam cortes bruscos e ajudam a “mascarar” carregamentos. O padrão prático é um CanvasLayer global com um ColorRect cobrindo a tela e um AnimationPlayer (ou Tween) para animar o alpha.

Passo a passo: Transição global reutilizável

  • Crie uma cena Transition.tscn com:
    • CanvasLayer (raiz)
    • ColorRect (nome: Fade) com cor preta e Mouse Filter = Ignore
    • AnimationPlayer
  • No ColorRect, marque LayoutFull Rect.
  • No AnimationPlayer, crie duas animações:
    • fade_out: alpha do Fade de 0 → 1 em 0.25–0.5s
    • fade_in: alpha de 1 → 0 em 0.25–0.5s
  • Transforme a cena em Autoload: Project Settings → Autoload → adicione Transition.tscn como Transition.

Script de controle (opcional, recomendado)

Anexe um script ao nó raiz do Autoload para expor funções simples:

Continue em nosso aplicativo e ...
  • Ouça o áudio com a tela desligada
  • Ganhe Certificado após a conclusão
  • + de 5000 cursos para você explorar!
ou continue lendo abaixo...
Download App

Baixar o aplicativo

extends CanvasLayer

@onready var anim: AnimationPlayer = $AnimationPlayer

func fade_out() -> void:
	anim.play("fade_out")
	await anim.animation_finished

func fade_in() -> void:
	anim.play("fade_in")
	await anim.animation_finished

func change_scene_with_fade(scene_path: String) -> void:
	await fade_out()
	get_tree().change_scene_to_file(scene_path)
	await get_tree().process_frame
	await fade_in()

Agora, quando for trocar de fase/menu, chame Transition.change_scene_with_fade("res://scenes/Level2.tscn").

Feedback visual de dano (flash, knockback leve e hit stop)

Conceito

Quando o jogador toma dano, três feedbacks simples aumentam muito a “sensação” de impacto: flash (piscar), pequeno empurrão (knockback) e hit stop (pausa curtíssima). Use com moderação para não atrapalhar o controle.

Flash com modulação (Sprite/AnimatedSprite2D)

  • No nó visual do personagem (ex.: AnimatedSprite2D), altere temporariamente modulate para uma cor clara (ex.: branco/avermelhado) e volte ao normal.
  • Faça isso via Tween para ficar suave e sem depender de timers manuais.
@onready var gfx: CanvasItem = $AnimatedSprite2D

func damage_flash() -> void:
	gfx.modulate = Color(1, 0.6, 0.6)
	var t := create_tween()
	t.tween_property(gfx, "modulate", Color(1, 1, 1), 0.12).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_OUT)

Hit stop (pausa curta)

Uma pausa de 0.05–0.1s dá “peso” ao golpe. Você pode pausar o SceneTree e garantir que a UI/Transição não pare (se necessário, configure Process Mode de nós específicos). Para um hit stop simples:

func hit_stop(duration := 0.06) -> void:
	get_tree().paused = true
	await get_tree().create_timer(duration, true, false, true).timeout
	get_tree().paused = false

Observação: o create_timer com parâmetros pode variar conforme a versão; se preferir robustez, use um Timer com Process Mode = Always em um Autoload de efeitos.

Knockback leve (sem quebrar o controle)

Se você já aplica impulso ao tomar dano, mantenha valores pequenos e parametrizados. Um padrão é aplicar uma velocidade instantânea e deixar a física resolver no próximo frame.

@export var knockback_strength := 220.0

func apply_knockback(from_global_pos: Vector2) -> void:
	var dir := (global_position - from_global_pos).normalized()
	velocity = dir * knockback_strength

Ajuste de dificuldade com parâmetros (sem “hardcode” espalhado)

Conceito

Dificuldade costuma ser um conjunto de números: dano, vida, velocidade de inimigos, frequência de spawn, tempo de invencibilidade, preço de itens, etc. Em vez de editar scripts em vários lugares, centralize em um recurso (Resource) ou em um Autoload de configuração. Assim você cria presets (Fácil/Normal/Difícil) e testa rapidamente.

Opção prática: Resource de dificuldade

  • Crie um script DifficultyData.gd:
extends Resource
class_name DifficultyData

@export var player_damage_multiplier := 1.0
@export var enemy_health_multiplier := 1.0
@export var enemy_speed_multiplier := 1.0
@export var invincibility_time_multiplier := 1.0
  • No FileSystem, crie recursos: easy.tres, normal.tres, hard.tres (New Resource → DifficultyData) e ajuste valores.
  • Crie um Autoload GameConfig.gd para manter a dificuldade atual:
extends Node

@export var difficulty: DifficultyData

func set_difficulty(res: DifficultyData) -> void:
	difficulty = res
  • Nos pontos do jogo onde calcula dano/vida/velocidade, multiplique pelos parâmetros. Exemplo (no inimigo):
var base_speed := 60.0

func _ready() -> void:
	var d := GameConfig.difficulty
	if d:
		base_speed *= d.enemy_speed_multiplier

Boa prática: mantenha “base_*” como valores originais e aplique multiplicadores ao iniciar a cena, evitando acumular multiplicações ao reiniciar.

Preparação do build: nome, versão, ícone e janela

Nome do pacote e versão

  • Project Settings → Application:
    • Config/Name: nome exibido do jogo
    • Config/Version: versão (ex.: 1.0.0)
  • Defina um padrão de versão e incremente a cada export (ex.: 0.1.0, 0.1.1…).

Ícone do aplicativo

  • Project Settings → ApplicationConfig/Icon (desktop).
  • Use PNG quadrado (ex.: 256×256 ou 512×512). Evite transparência excessiva para ícones pequenos.
  • Para mobile, o ícone final pode ser configurado no preset de export (Android/iOS) e/ou via configurações específicas do template.

Configurações de janela e resolução

O objetivo é garantir que o jogo fique legível em diferentes telas sem distorção.

  • Project Settings → DisplayWindow:
    • Size/Viewport Width e Height: resolução base (ex.: 1280×720)
    • Mode: Windowed/Fullscreen conforme seu alvo
    • Stretch/Mode: geralmente canvas_items para 2D
    • Stretch/Aspect: keep ou keep_width/keep_height conforme seu layout

Teste rápido: rode o jogo e redimensione a janela (desktop) para verificar UI, câmera e limites.

Export templates: requisito obrigatório para exportar

Conceito

Para exportar, a Godot precisa dos Export Templates da mesma versão do editor. Sem eles, os presets aparecem, mas a exportação falha.

Passo a passo: instalar templates

  • Editor: EditorManage Export Templates.
  • Clique em Download and Install.
  • Confirme que a versão dos templates corresponde à versão do seu editor.

Exportação para Desktop (Windows / Linux / macOS)

Conceito

No desktop, o fluxo é: criar um preset de export, ajustar opções (nome do executável, ícone, arquitetura), exportar e testar o executável em uma pasta “limpa”.

Passo a passo: criar presets e exportar

  • Vá em ProjectExport....
  • Clique em Add... e crie presets para:
    • Windows Desktop
    • Linux/X11 (ou Linux)
    • macOS
  • Em cada preset:
    • Defina Export Path (ex.: builds/windows/MyGame.exe)
    • Marque Embed PCK se quiser um único arquivo (quando disponível/adequado) ou exporte com PCK separado
    • Revise opções de arquitetura (x86_64, arm64 quando aplicável)
  • Clique em Export Project (ou Export All).

Verificações práticas pós-export (desktop)

  • Execute o jogo fora do editor (duplo clique no executável).
  • Teste em uma pasta sem o projeto (para garantir que não depende de arquivos do editor).
  • Confirme: ícone, nome da janela, resolução inicial, áudio e input.

Exportação para Android

Conceito

No Android, você exporta um .apk (instalação direta) ou .aab (publicação em loja). O ponto crítico é configurar o ambiente (SDK/JDK) e assinar o app (keystore) para builds finais.

Requisitos e configuração (passos práticos)

  • Instale o Android Studio (para obter SDK/Platform Tools) e um JDK compatível com sua versão da Godot.
  • No Godot: EditorEditor Settings → procure por Android e configure caminhos do SDK/JDK (quando solicitado).
  • Em ProjectInstall Android Build Template (se o seu fluxo exigir template customizável).

Passo a passo: preset Android

  • ProjectExport...Add... → Android.
  • Defina:
    • Package/Unique Name (ex.: com.seustudio.seujogo)
    • Version Code (inteiro, ex.: 1, 2, 3…)
    • Version Name (ex.: 1.0.0)
  • Assinatura:
    • Para testes locais, use debug se disponível
    • Para release, configure Keystore e Key Alias no preset
  • Exporte para .apk e instale no dispositivo (USB) para testar.

Checklist rápido Android

  • Rotação e aspect ratio: o jogo não deve “cortar” UI.
  • Input: toque/botões virtuais (se houver) e back button (se você usar).
  • Performance: partículas e pós-processamento não devem derrubar FPS.

Exportação para iOS

Conceito

No iOS, o fluxo geralmente envolve gerar um projeto para Xcode e compilar/assinar com uma conta Apple Developer. O ponto crítico é o ambiente macOS com Xcode e certificados/provisioning.

Passos práticos (visão operacional)

  • Em um Mac com Xcode instalado, abra ProjectExport... e adicione o preset iOS.
  • Configure:
    • Bundle Identifier (ex.: com.seustudio.seujogo)
    • Versão e build number
    • Orientação de tela
  • Exporte para um projeto iOS e abra no Xcode.
  • No Xcode: selecione Team, configure Signing, conecte o dispositivo e rode.

Observação: se o objetivo for apenas validar o jogo em mobile sem entrar no ecossistema Apple, priorize Android para testes rápidos e deixe iOS para a etapa em que você já tem conta/certificados.

Checklist de testes finais (antes de distribuir)

Performance básica

  • Sem quedas perceptíveis em momentos de ação (partículas, múltiplos inimigos, UI).
  • Sem stutter ao trocar de cena (use transição e evite carregar recursos pesados no meio do gameplay).
  • Monitore no Debugger do editor e repita o teste no build exportado.

Resolução e escala

  • UI não sai da tela em 16:9, 16:10 e ultrawide (desktop).
  • Texto legível e botões clicáveis em resoluções menores.
  • Câmera e limites de fase corretos em diferentes aspect ratios.

Input

  • Teclado/controle: todas as ações respondem e não conflitam.
  • Mobile: toques/gestos (se aplicável) e botões virtuais com área suficiente.
  • Foco de janela: ao alt-tab, o jogo não “trava” em estados errados.

Áudio

  • Música e SFX com volumes equilibrados.
  • Sem clipping/distorção em picos.
  • Configurações de volume (se existirem) persistem e aplicam corretamente.

Salvamento

  • Salvar e carregar funcionam no build exportado (caminhos corretos).
  • Se o arquivo não existir, o jogo cria defaults sem erro.
  • Compatibilidade simples de versão: ao mudar versão, o jogo não quebra com save antigo (ao menos falha de forma controlada).

Fluxo de estados e transições

  • Do menu para o jogo, do jogo para pause, game over e retorno ao menu sem travar.
  • Transições (fade) não ficam presas em tela preta.
  • Reiniciar fase não duplica nós (UI, música, autoloads) e não acumula timers/partículas.

Empacotamento e apresentação

  • Nome do app e versão corretos.
  • Ícone correto no executável/aplicativo.
  • Pasta de build contém apenas o necessário (executável + pck/dlls quando aplicável).

Agora responda o exercício sobre o conteúdo:

Ao criar um efeito de poeira ao aterrissar com GPUParticles2D, qual abordagem melhor garante que o efeito dispare apenas no momento em que o personagem toca o chão?

Você acertou! Parabéns, agora siga para a próxima página

Você errou! Tente novamente.

Para evitar repetição contínua, o emissor deve ficar desligado e ser acionado somente quando ocorrer a mudança de estado: antes estava no ar e agora está no chão. Isso dispara o efeito uma única vez por aterrissagem.

Capa do Ebook gratuito Godot do Zero: Criando seu Primeiro Jogo 2D com GDScript
100%

Godot do Zero: Criando seu Primeiro Jogo 2D com GDScript

Novo curso

17 páginas

Baixe o app para ganhar Certificação grátis e ouvir os cursos em background, mesmo com a tela desligada.