Voltar para o Blog
Quest Log

Mecânicas de Jogos de Cartas: Guia para Prototipar

Cartas de baralho digitais abertas em leque com energia brilhante, ilustração plana sem texto.

Mecânicas de jogos de cartas explicadas com exemplos reais e como prototipar cada uma na Godot 4: deckbuilding, mana, sinergia, aleatoriedade e TCG.

Jogos de cartas digitais parecem complicados porque uma partida de Slay the Spire ou Hearthstone tem centenas de interações possíveis, mas por baixo quase todas usam o mesmo punhado de peças. Entender as mecânicas de jogos de cartas é entender como embaralhar, comprar, pagar um custo, combinar efeitos e lidar com o acaso. Cada uma dessas ideias é pequena isolada, e o jogo nasce da forma como você encaixa elas. Neste guia eu explico as mecânicas centrais do gênero, dou um exemplo real de cada uma e mostro como prototipar na Godot 4 com GDScript tipado.

O foco é o esqueleto que se repete em quase todo card game, do colecionável ao roguelike. Se você quer o panorama de como mecânica se encaixa em um projeto maior, vale ler antes o que são mecânicas de jogo e tipos de mecânicas de jogo. Aqui a gente mergulha no recorte de cartas.

Deckbuilding: o baralho como recurso

Deckbuilding é a mecânica onde o próprio baralho é algo que você constrói e melhora, em vez de ser fixo. A decisão de qual carta adicionar, e qual carta remover, é parte central da estratégia. Um baralho menor e mais focado costuma ser mais forte que um grande e disperso, porque você compra o que importa com mais frequência.

O exemplo mais limpo é Dominion, o jogo de tabuleiro que fundou o gênero: todo mundo começa igual e vai comprando cartas de um mercado comum para moldar o próprio motor. Na versão digital, o deckbuilding aparece em Slay the Spire, onde cada recompensa de combate oferece três cartas e você escolhe uma ou pula.

Para prototipar, a peça base é o ciclo de três pilhas: compra, mão e descarte. Você embaralha a pilha de compra, puxa cartas para a mão, joga, manda o que usou para o descarte e, quando a compra esvazia, reembaralha o descarte de volta. Esse ciclo é quase todo manipulação de Array, então ele é acessível mesmo para quem está começando. Se você quer um passo a passo completo desse loop, o tutorial de como fazer um jogo deck builder desce ao detalhe.

Gerenciamento de mão: quantas cartas você segura

A mão é o conjunto de cartas disponíveis para jogar no turno. Gerenciar a mão é decidir o que usar agora e o que guardar, dentro de um limite. Quase todo jogo impõe um tamanho máximo de mão (sete em Magic, dez em Hearthstone), e passar desse limite força o descarte. Esse teto existe para você não acumular recurso infinito e para criar a tensão de ter que gastar.

Em Hearthstone, o limite de dez cartas na mão faz com que comprar demais vire desperdício: se a mão está cheia, a carta comprada é queimada. Essa punição transforma "comprar carta" em algo que tem custo escondido, e isso é design, não acidente.

No protótipo, a mão é outro Array[Carta]. A regra de limite vira uma checagem no momento da compra: se a mão atingiu o teto, a carta comprada é descartada ou queimada em vez de entrar. Manter a mão como Array separado da pilha de compra deixa essa regra trivial de aplicar.

Custo e recurso: a mana que limita suas jogadas

Quase todo jogo de cartas tem um recurso que limita quantas e quais cartas você joga por turno. Em Magic é a mana vinda de terrenos; em Hearthstone é o cristal de mana que cresce um por turno até dez; em Slay the Spire é a energia, geralmente três por turno. Esse recurso é o que impede você de jogar a mão inteira de uma vez e é o que dá peso à ordem das jogadas.

O recurso resolve dois problemas de uma vez: ele regula o ritmo (o jogo não acaba no primeiro turno) e cria uma curva de decisão (uma carta cara e forte contra duas baratas e fracas). Projetar o custo de cada carta em relação ao efeito dela é o coração do balanceamento de um card game. Se quiser se aprofundar nessa parte numérica, veja o guia de balanceamento de jogos com fórmulas e técnicas.

Para prototipar, basta uma variável de energia que você reseta no início do turno e subtrai quando uma carta é jogada. Antes de jogar, você checa se a energia atual cobre o custo da carta. É uma comparação de inteiros, mas é o que separa um amontoado de cartas de um jogo.

Curso de Godot
Quer fazer seu primeiro jogo na Godot?

No curso de Godot 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 Godot
Suporte no WhatsAppAcesso vitalícioGarantia de 7 dias

Sinergia e combo: quando duas cartas valem por cinco

Sinergia é quando cartas valem mais juntas do que separadas. Combo é a sequência específica que, na ordem certa, explode em efeito. Essa mecânica é o que torna a construção de baralho interessante: você não escolhe as cartas mais fortes isoladas, escolhe as que conversam entre si.

Em Slay the Spire, cartas que ganham valor "sempre que você joga uma carta de ataque" criam motores inteiros em volta de um arquétipo. Em Magic, decks de combo buscam uma sequência que vence a partida de um golpe. O design aqui é dar ao jogador peças que se encaixam, sem que uma única peça seja obrigatória.

No protótipo, sinergia nasce de dois lugares: efeitos que leem o estado atual (por exemplo, "cause dano igual ao número de cartas no descarte") e efeitos que disparam a partir de eventos (por exemplo, "sempre que uma carta de ataque for jogada"). Para o segundo caso, um sistema de signals da Godot encaixa bem: a carta jogada emite um sinal e outras cartas ou relíquias reagem. Começar com efeitos que apenas leem o estado é o caminho mais simples antes de montar o sistema de eventos.

Aleatoriedade e mitigação: controlar o acaso

Aleatoriedade é a alma do gênero: você embaralha e não sabe a ordem da compra. É isso que faz cada partida ser diferente. O problema é que acaso demais vira frustração, então todo bom jogo de cartas oferece formas de mitigar a sorte.

As técnicas clássicas de mitigação são o mulligan (trocar uma mão inicial ruim, presente em Magic e Hearthstone), cartas que compram outras ao serem jogadas (os cantrips, que diluem a variância), o pity timer (garantir algo bom depois de uma sequência de azar) e simplesmente manter o baralho enxuto para subir a chance de comprar o que importa. Note como mitigação e deckbuilding se conectam: baralho menor é menos aleatório.

No protótipo, a aleatoriedade é o shuffle() do Array. A mitigação costuma ser lógica em cima dele: um mulligan devolve a mão ao baralho e recompra; um cantrip simplesmente chama a função de comprar como parte do efeito. Se você quer resultado reproduzível para depurar, troque o shuffle() global por um RandomNumberGenerator com seed fixa.

Roguelike de cartas e colecionável: dois jeitos de montar baralho

Vale separar duas famílias do gênero porque elas montam o baralho em momentos diferentes.

O roguelike de cartas, popularizado por Slay the Spire, constrói o baralho durante a run. Você começa fraco, pega cartas e relíquias ao longo da partida e, se morre, recomeça do zero. A graça está na escolha sob incerteza: você não sabe o que vem adiante.

O colecionável, ou TCG, como Hearthstone e Magic: The Gathering, separa a montagem do baralho da partida. Você reúne uma coleção de cartas fora do jogo (comprando pacotes, criando cartas) e monta o baralho antes de sentar para jogar. A mesma lista enfrenta vários adversários sem mudar no meio.

Para o protótipo, a diferença é onde o baralho é definido. No roguelike, o baralho é um Array que cresce com funções de recompensa durante a partida. No TCG, o baralho é um Array montado a partir de uma coleção maior antes de a partida começar. A representação da carta e o ciclo de compra são idênticos nos dois, o que muda é quem preenche o Array e quando.

Prototipando na Godot 4: carta, baralho e compra

Com as mecânicas no lugar, vamos ao código. A carta é dado puro, então ela estende Resource, não Node. Assim você edita cada carta pelo Inspector, salva em arquivos .tres e ganha tipagem estática.

# carta.gd
# A carta e DADO, nao comportamento: por isso estende Resource.
class_name Carta
extends Resource

# Enum tipado para o tipo. Evita erro de digitacao e deixa
# o match limpo na hora de resolver o efeito.
enum Tipo {
    ATAQUE,   # causa dano
    DEFESA,   # gera bloqueio
    COMPRA,   # faz o jogador comprar cartas
}

@export var nome: String = "Carta"
@export var custo: int = 1          # energia necessaria para jogar
@export var tipo: Tipo = Tipo.ATAQUE
@export var valor: int = 6          # dano, bloqueio ou nro de cartas

Agora o baralho e o ciclo de pilhas. Repare que tudo são Array[Carta] tipados e que o estado real da partida vive aqui, não nas cartas desenhadas na tela:

# baralho.gd
# Controla as tres pilhas e o recurso de energia.
extends Node

var pilha_compra: Array[Carta] = []
var mao: Array[Carta] = []
var descarte: Array[Carta] = []

const TAMANHO_MAO_MAX: int = 10
var energia: int = 3

# Monta a pilha de compra a partir de uma lista de cartas e embaralha.
func montar_baralho(cartas: Array[Carta]) -> void:
    pilha_compra = cartas.duplicate()
    mao.clear()
    descarte.clear()
    pilha_compra.shuffle()   # aleatoriedade: ordem imprevisivel

# Compra UMA carta. Reembaralha o descarte se a compra esvaziar.
func comprar_carta() -> Carta:
    if pilha_compra.is_empty():
        _reembaralhar_descarte()
    if pilha_compra.is_empty():
        return null   # nao ha mais cartas em lugar nenhum

    var carta: Carta = pilha_compra.pop_back()

    # Gerenciamento de mao: respeita o limite, senao queima a carta.
    if mao.size() >= TAMANHO_MAO_MAX:
        descarte.append(carta)
        return null

    mao.append(carta)
    return carta

# Compra N cartas de uma vez (inicio de turno, por exemplo).
func comprar(quantidade: int) -> void:
    for i in quantidade:
        comprar_carta()

func _reembaralhar_descarte() -> void:
    pilha_compra = descarte.duplicate()
    descarte.clear()
    pilha_compra.shuffle()

Falta aplicar o custo e resolver o efeito. É aqui que entram a mana e o match no enum do tipo:

# Tenta jogar uma carta da mao. Devolve true se conseguiu.
func jogar_carta(indice: int) -> bool:
    var carta: Carta = mao[indice]

    # Custo/recurso: so joga se a energia cobrir o custo.
    if carta.custo > energia:
        return false

    energia -= carta.custo

    # Resolve o efeito pelo tipo, sem if gigante.
    match carta.tipo:
        Carta.Tipo.ATAQUE:
            _causar_dano(carta.valor)
        Carta.Tipo.DEFESA:
            _ganhar_bloqueio(carta.valor)
        Carta.Tipo.COMPRA:
            comprar(carta.valor)   # cantrip: carta que compra outras

    mao.remove_at(indice)
    descarte.append(carta)
    return true

Com esse esqueleto você já tem deckbuilding (montar e reembaralhar), gerenciamento de mão (o limite), custo de recurso (a energia), uma ponta de sinergia (o tipo COMPRA que vira cantrip) e aleatoriedade (o shuffle). As funções _causar_dano e _ganhar_bloqueio ficam a seu cargo conforme o jogo. Para uma implementação completa com interface e cartas na tela, o tutorial de como fazer um jogo de cartas no Godot continua daqui. E se você quer ver essas ideias aplicadas em outros gêneros, a lista de exemplos de mecânicas de jogo ajuda a comparar.

Por onde começar

A ordem que funciona é essa: primeiro acerte o ciclo de compra, mão e descarte com cartas simples de dano e bloqueio. Depois adicione o custo de energia. Só então introduza tipos novos, efeitos que leem o estado e, por último, o sistema de eventos para sinergias. Aleatoriedade você ganha de graça com o shuffle, e a mitigação você acrescenta quando sentir onde o acaso incomoda.

A armadilha mais comum é querer resolver efeito complexo antes de o loop básico girar redondo. Cartas que copiam outras, que mudam de custo, que disparam em cadeia: tudo isso é fascinante e tudo isso depende de o baralho, a mão e o descarte funcionarem sem bug. Construa o chão antes do teto, teste jogando de verdade e deixe a complexidade chegar quando a base aguentar.

Perguntas frequentes

Qual a diferença entre deckbuilding e um TCG colecionável?

No deckbuilding roguelike, como Slay the Spire, você começa com um baralho fraco e constrói ele durante a própria partida, escolhendo cartas que aparecem no caminho. No TCG colecionável, como Hearthstone ou Magic, você monta o baralho antes da partida a partir de uma coleção que adquire fora do jogo, e esse baralho não muda no meio da run. Um é construção dentro da partida, o outro é construção antes dela.

Como representar uma carta e um baralho em GDScript tipado?

A carta é dado puro, então vira um Resource com class_name Carta e campos @export tipados (nome, custo, tipo, valor). O baralho é um Array[Carta]. Você embaralha com o método shuffle() do Array e compra removendo o último elemento com pop_back(). O estado da partida vive nesses Arrays tipados, não nas cartas desenhadas na tela.

Como deixar a aleatoriedade das cartas menos frustrante?

Você aplica mitigação. As técnicas comuns são mulligan (trocar a mão inicial ruim), cantrips (cartas que se pagam comprando outra ao serem usadas), pity timer (garantir uma carta boa depois de N compras sem sorte) e reduzir o tamanho do baralho para aumentar a chance de comprar o que importa. O objetivo é manter a surpresa sem punir o jogador por azar puro.

O que é sinergia e combo em um jogo de cartas?

Sinergia é quando duas ou mais cartas valem mais juntas do que separadas, porque uma potencializa a outra. Combo é a sequência específica de cartas que, jogada na ordem certa, gera um efeito muito acima do normal. Projetar sinergia é dar ao jogador peças que conversam entre si, e é isso que transforma comprar cartas em decisão interessante.

Preciso de servidor para prototipar mecânicas de cartas na Godot?

Não para o protótipo. Toda a lógica de baralho, mão, custo e efeito roda local, manipulando Arrays de dados. Servidor só entra quando você vai fazer partidas online entre jogadores, que é um problema separado de rede e sincronização. Valide a mecânica sozinho antes de pensar em multiplayer.