Voltar para o Blog
Quest Log

Sistemas de Progressão em Jogos Explicados: XP, Skill Tree e Pacing

Personagem subindo uma escadaria de níveis com uma árvore de habilidades ao fundo

Entenda como funciona um sistema de progressão de jogo: curvas de XP, árvore de skills, desbloqueios e pacing, com código GDScript pronto para usar.

Sistemas de Progressão em Jogos Explicados: XP, Skill Tree e Pacing

Um sistema de progressão de jogo é o motivo de alguém jogar "só mais uma fase" às duas da manhã. É a estrutura que transforma tempo investido em poder, opções e identidade. Quando funciona, o jogador nem percebe que existe um sistema; quando falha, o jogo vira ou uma escadaria chata de grind ou um buffet onde tudo destrava cedo demais e não sobra motivo pra continuar.

A boa notícia: progressão não é mágica de designer veterano. São três peças que você consegue projetar e programar separadamente: a moeda de progresso (XP, na maioria dos casos), a estrutura de desbloqueio (níveis, árvore de skills, itens) e o ritmo em que tudo isso chega na mão do jogador (pacing). Esse artigo passa pelas três, com código GDScript do Godot 4 que roda como está.

O que um sistema de progressão precisa responder

Antes de abrir o editor, vale responder três perguntas no papel:

  1. O que o jogador faz pra progredir? Matar inimigos, completar quests, explorar, coletar. Isso define o que o seu jogo recompensa, e o jogador vai fazer mais daquilo que dá XP. Se só combate dá XP, ninguém explora.
  2. O que a progressão entrega? Números maiores (mais vida, mais dano), opções novas (habilidades, builds) ou acesso novo (áreas, modos). Os três são sensações diferentes.
  3. Em quanto tempo? Um roguelike entrega progresso em minutos. Um RPG, em dezenas de horas. O mesmo sistema com pacing errado pro gênero quebra o jogo inteiro.

A distinção entre número maior e opção nova é a que mais separa jogos bons de medianos. Subir de nível e ganhar +5 de vida é progressão vertical: você fica mais forte, mas joga igual. Destravar um dash ou um pulo duplo é progressão horizontal: o jogo muda de verdade. Os melhores sistemas misturam os dois, com o vertical dando a sensação constante de avanço e o horizontal marcando os momentos memoráveis.

A curva de XP: o coração do sistema de progressão

Quase todo jogo com níveis usa a mesma ideia: cada nível custa mais XP que o anterior. Se o custo fosse fixo, o jogador subiria de nível cada vez mais rápido conforme fica forte, e os níveis perderiam valor. A curva crescente compensa o fato de que inimigos de fim de jogo dão mais XP.

As duas famílias mais comuns:

Curva polinomial. O custo cresce com o nível elevado a um expoente, geralmente entre 1.5 e 2.5. É previsível e fácil de ajustar: expoente maior, fim de jogo mais lento.

Curva exponencial. O custo multiplica por um fator a cada nível (1.1x, 1.15x). Cresce devagar no começo e explode no final. Funciona bem em jogos onde o ganho de XP também escala agressivamente, como idle games.

Pra maioria dos projetos, a polinomial resolve. Em código:

extends Node

signal xp_changed(current_xp, xp_needed)
signal level_up(new_level)

var level := 1
var current_xp := 0

const BASE_XP := 100
const EXPONENT := 1.8

func xp_for_level(lvl: int) -> int:
    # Custo pra ir do nível lvl pro lvl + 1.
    return int(BASE_XP * pow(lvl, EXPONENT))

func add_xp(amount: int) -> void:
    current_xp += amount
    # while em vez de if: um ganho grande pode subir mais de um nível.
    while current_xp >= xp_for_level(level):
        current_xp -= xp_for_level(level)
        level += 1
        level_up.emit(level)
    xp_changed.emit(current_xp, xp_for_level(level))

Com BASE_XP = 100 e expoente 1.8, o nível 2 custa 100 XP, o nível 5 custa cerca de 1.200 e o nível 10 passa de 6.000. Ajustar a curva inteira é mexer em duas constantes, e é por isso que vale centralizar a fórmula numa função em vez de espalhar valores mágicos pelo projeto.

Um detalhe de arquitetura: esse script funciona bem como autoload (singleton), porque XP é estado global do jogador. Os sinais xp_changed e level_up deixam a HUD, o som de level up e os efeitos visuais se conectarem sem o sistema de progressão saber que eles existem.

E uma regra prática de design que economiza retrabalho: faça os primeiros níveis chegarem rápido. O jogador precisa entender o loop de recompensa nos primeiros minutos. Se o primeiro level up demora meia hora, boa parte das pessoas larga antes de sentir o gostinho.

Árvore de skills: dados primeiro, interface depois

O erro clássico ao programar uma skill tree é começar pela interface, com cada botão da árvore carregando sua própria lógica. Aí adicionar uma skill nova vira cirurgia. O caminho são dados separados da apresentação: a árvore é uma estrutura de dados com pré-requisitos, e a interface só lê essa estrutura.

Uma árvore de skills, no fundo, é um grafo de dependências: cada skill tem um custo e uma lista de skills que precisam estar destravadas antes. Dá pra modelar com um dicionário simples:

extends Node

signal skill_unlocked(skill_id)

var skill_points := 0
var unlocked: Array[String] = []

var skills := {
    "golpe_forte": {"cost": 1, "requires": []},
    "investida": {"cost": 1, "requires": []},
    "golpe_giratorio": {"cost": 2, "requires": ["golpe_forte"]},
    "execucao": {"cost": 3, "requires": ["golpe_forte", "investida"]},
}

func can_unlock(id: String) -> bool:
    if id in unlocked:
        return false
    var skill = skills[id]
    if skill_points < skill["cost"]:
        return false
    for req in skill["requires"]:
        if not req in unlocked:
            return false
    return true

func unlock(id: String) -> bool:
    if not can_unlock(id):
        return false
    skill_points -= skills[id]["cost"]
    unlocked.append(id)
    skill_unlocked.emit(id)
    return true

func has_skill(id: String) -> bool:
    return id in unlocked

O resto do jogo só pergunta has_skill("investida") na hora de decidir se o input de dash faz alguma coisa. A interface da árvore percorre o dicionário, desenha um botão por skill e pinta de cinza o que can_unlock() recusar. Skill nova é uma linha no dicionário, sem tocar em lógica.

Em projeto maior, vale trocar o dicionário por Resources customizados (um .tres por skill), que dão editor visual e checagem de tipo. A estrutura lógica continua idêntica.

No design da árvore em si, duas armadilhas aparecem o tempo todo:

  • Skill de imposto. Aquele nó obrigatório e chato ("+ 3% de dano") que só existe pra alcançar a skill boa. Uma ou outra passa, mas uma árvore cheia delas transforma escolha em burocracia.
  • Escolha sem informação. Pedir que o jogador escolha entre três ramos na primeira hora, antes de entender o combate, não é profundidade, é chute. Ou deixe os primeiros pontos serem baratos de realocar, ou segure as bifurcações grandes pra quando o jogador já sabe o que gosta.
Próximo nível
Quer aprender isso na prática?

No CursoGame.Dev você sai dos tutoriais soltos e constrói jogos publicáveis, com trilha progressiva, quests práticas e feedback real.

Conhecer a plataforma
+500 alunos4.9/5Garantia 7 dias

Desbloqueios: progressão além dos números

Nem toda progressão é barra de XP. Desbloqueio é qualquer conteúdo que existe no jogo mas ainda não está disponível: área nova, arma nova, modo de jogo, personagem, receita de craft. E desbloqueio bem feito segue uma lógica diferente da curva de XP: ele funciona melhor amarrado a marcos do que a acúmulo.

A diferença na prática: "destrave a besta ao derrotar o chefe da floresta" cria um momento. "Destrave a besta ao atingir 4.000 pontos de caça" cria uma tarefa. Acúmulo tem lugar (maestria de arma, por exemplo), mas os desbloqueios que estruturam o jogo rendem mais como marcos.

Metroidvanias são a aula definitiva do assunto: a progressão inteira é desbloqueio de habilidade que reabre o mapa. O pulo duplo não é só um poder, é uma chave. Quando você projeta um desbloqueio assim, a pergunta certa não é "o que o jogador ganha?", é "o que o jogador passa a poder fazer que antes não podia?". Se a resposta é "nada, só fica mais forte", é progressão vertical disfarçada.

Um padrão que uso pra manter desbloqueios organizados é tratá-los como flags centralizadas, no mesmo espírito da skill tree: um conjunto de IDs destravados, sinais pra avisar o resto do jogo, e o conteúdo perguntando "estou liberado?" em vez de cada porta do mapa carregar lógica própria.

Pacing: o ritmo que segura o jogador

Pacing é a parte invisível e a mais difícil de acertar, porque não tem fórmula, tem teste. É o intervalo entre recompensas ao longo do jogo inteiro. Os princípios que guiam o ajuste:

Comece denso, termine espaçado. Recompensas frequentes no início ensinam o loop e criam o hábito. Conforme o jogador investe no jogo, ele aceita intervalos maiores, porque cada recompensa pesa mais. O contrário (começo lento, final atropelado) é receita de abandono na primeira hora.

Alterne tamanhos de recompensa. Um fluxo constante de recompensas pequenas vira ruído; só recompensas grandes e raras vira deserto. O ritmo bom intercala: XP pinga sempre, level up a cada tantos minutos, skill nova de vez em quando, desbloqueio de área como evento.

Nunca deixe a barra parada. O jogador deve sempre enxergar o próximo objetivo de progressão a uma distância alcançável. Se ele olha a barra de XP e pensa "isso não anda", o sistema falhou, mesmo que a matemática esteja certa.

Cuidado com o grind como conserto. Se o teste mostra que o jogador chega forte demais no chefe, a tentação é encarecer a curva. Só que isso pune todo mundo com mais repetição. Antes de mexer na curva, olhe a fonte: talvez uma quest específica pague XP demais, ou um inimigo fácil demais seja farmável.

Pra ajustar pacing você precisa enxergar os números. Um log simples já muda o jogo durante o desenvolvimento:

# Conectado ao sinal level_up do sistema de XP.
func _on_level_up(new_level: int) -> void:
    var minutes = Time.get_ticks_msec() / 60000.0
    print("Nível %d aos %.1f minutos de jogo" % [new_level, minutes])

Rode uma sessão de teste, olhe os intervalos entre level ups e compare com a intenção. Se você queria um level up a cada 10 minutos no meio do jogo e o log mostra 25, não precisa de playtest formal pra saber onde mexer.

Por onde começar no seu projeto

Se o seu jogo ainda não tem progressão, a ordem que recomendo é a mais barata de iterar:

  1. Defina no papel as três respostas do início: o que dá progresso, o que a progressão entrega, em quanto tempo.
  2. Implemente só o XP com a curva polinomial e ligue numa barra na HUD. Jogue. Sinta o ritmo do pingar de XP antes de construir qualquer coisa em cima.
  3. Adicione níveis com uma recompensa vertical simples (vida, dano) e calibre a curva até os intervalos parecerem certos.
  4. Só então construa a skill tree ou os desbloqueios, que são as peças caras de produzir.

Progressão é um sistema que se ajusta jogando, não planilhando. A planilha te dá o ponto de partida; o playtest te diz a verdade. Comece pequeno, com uma curva e duas constantes, e deixe o sistema crescer junto com o jogo.