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ó
GPUParticles2Dcomo filho (ex.:LandingDust). - No Inspector, configure:
One Shot= ligadoEmitting= desligadoAmount= 12–24Lifetime= 0.25–0.5Process Material= crie umParticleProcessMateriale ajusteInitial Velocity,GravityeScale
- 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_floorDica: 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.tscncom:CanvasLayer(raiz)ColorRect(nome:Fade) com cor preta eMouse Filter= IgnoreAnimationPlayer
- No
ColorRect, marqueLayout→Full Rect. - No
AnimationPlayer, crie duas animações:fade_out: alpha doFadede 0 → 1 em 0.25–0.5sfade_in: alpha de 1 → 0 em 0.25–0.5s
- Transforme a cena em Autoload: Project Settings → Autoload → adicione
Transition.tscncomoTransition.
Script de controle (opcional, recomendado)
Anexe um script ao nó raiz do Autoload para expor funções simples:
- Ouça o áudio com a tela desligada
- Ganhe Certificado após a conclusão
- + de 5000 cursos para você explorar!
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 temporariamentemodulatepara 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 = falseObservaçã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_strengthAjuste 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.gdpara 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_multiplierBoa 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 jogoConfig/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 →
Application→Config/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 →
Display→Window:Size/Viewport WidtheHeight: resolução base (ex.: 1280×720)Mode: Windowed/Fullscreen conforme seu alvoStretch/Mode: geralmentecanvas_itemspara 2DStretch/Aspect:keepoukeep_width/keep_heightconforme 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:
Editor→Manage 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
Project→Export.... - 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 PCKse quiser um único arquivo (quando disponível/adequado) ou exporte com PCK separado - Revise opções de arquitetura (x86_64, arm64 quando aplicável)
- Defina
- Clique em
Export Project(ouExport 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:
Editor→Editor Settings→ procure porAndroide configure caminhos do SDK/JDK (quando solicitado). - Em
Project→Install Android Build Template(se o seu fluxo exigir template customizável).
Passo a passo: preset Android
Project→Export...→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
KeystoreeKey Aliasno preset
- Exporte para
.apke 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
Project→Export...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).