Voltar para o Blog
Quest Log

Como Fazer um Jogo de Pesca: Mecânica, Progressão e Código na Godot

Cena de pesca em pixel art ao entardecer, personagem em um barco com a linha lançada no lago e uma barra de tensão de minigame visível na tela

Como fazer um jogo de pesca na Godot 4: loop de lançar e fisgar, minigame de tensão em GDScript tipado, tabela de raridade e o escopo mínimo pra terminar.

Como fazer um jogo de pesca é uma daquelas perguntas que eu gosto de receber, porque a resposta cabe num projeto pequeno e honesto. A pesca é um dos loops mais antigos e mais à prova do tempo do design de jogos: lançar a linha, esperar, fisgar, coletar. Quatro verbos, um minigame curto no meio e uma coleção pra preencher. É pequeno o suficiente pra um dev solo terminar e profundo o suficiente pra sustentar um jogo inteiro, como o gênero vem provando nos últimos anos. Neste guia eu desmonto a anatomia do gênero, detalho o design do minigame de fisgada e implemento a parte central na Godot 4, com GDScript tipado. No final, o corte de escopo que eu faria num primeiro projeto.

Por que a pesca virou gênero, não minigame

Durante muito tempo a pesca foi acessório: o minigame dentro do jogo maior. A pesca de Stardew Valley é o exemplo clássico, um minigame de barra e precisão que muita gente ama e muita gente odeia, mas que todo mundo reconhece em meio segundo. O que mudou recentemente é que a pesca saiu do papel de coadjuvante.

Dredge pegou o loop e misturou com horror: a mecânica é a mesma calma de sempre, mas o que vem na linha, e o que acontece quando a noite cai, transforma cada lançamento em aposta. Webfishing foi na direção oposta e virou fenômeno cozy multiplayer, um jogo em que a pesca é quase uma desculpa pra sentar à beira do lago com outras pessoas. Dois jogos, o mesmo esqueleto, tons completamente diferentes. Isso é o sinal de um gênero saudável: o loop aguenta reinterpretação.

E o motivo de o loop aguentar é emocional, não técnico. A pesca combina duas coisas que raramente andam juntas: calma e surpresa. A espera é relaxante, de baixa exigência, perfeita pra onda cozy. Mas cada lançamento é uma caixa fechada, e a pergunta "o que vem agora?" é o motor que faz o jogador lançar de novo. Se você entender esse contraste, entendeu o gênero.

Como fazer um jogo de pesca: a anatomia do loop

Todo jogo de pesca, do mais zen ao mais sombrio, se apoia nos mesmos quatro blocos.

O loop central. Lançar a linha, esperar até a mordida, vencer o minigame de fisgada, coletar o peixe. O ciclo completo dura entre dez segundos e um minuto, e essa duração curta é uma decisão de design, não um acidente: o jogador precisa poder dizer "só mais uma" sem se comprometer com nada. Compare com um farming sim, em que o retorno do plantio demora dias de jogo. Se você já leu meu guia sobre como estruturar um jogo de fazenda, vai reconhecer o parentesco: os dois gêneros são loops de espera e recompensa, mas a pesca comprime a espera pra segundos.

Progressão por coleção. O que puxa o jogador de sessão em sessão não é ficar mais forte, é completar o álbum. Peixes comuns, incomuns, raros e lendários; espécies que só aparecem em certo bioma, em certo horário, em certo clima. Cada regra dessas cria um objetivo implícito ("preciso voltar aqui de noite") sem precisar de uma quest escrita. A coleção é a espinha do jogo, e o menu de coleção, com silhuetas dos peixes ainda não capturados, é uma das telas mais importantes do projeto.

Economia. Peixe vira dinheiro, dinheiro vira vara melhor, vara melhor alcança peixe mais difícil. É um ciclo de reinvestimento simples, mas ele precisa ser desenhado com cuidado: se o peixe comum paga bem demais, ninguém persegue o raro; se o upgrade de vara é barato demais, a progressão acaba em uma hora. Os princípios que eu detalho no guia de economia de jogo valem inteiros aqui, em escala miniatura, o que torna o gênero um laboratório ótimo pra aprender balanceamento.

O gancho emocional. Calma na superfície, surpresa na linha. Na prática isso significa duas coisas: a espera precisa ser agradável (água animada, som ambiente, nada gritando na tela) e o resultado precisa ser incerto (raridade sorteada, variação de tamanho, um item estranho de vez em quando). Um jogo de pesca sem surpresa é um relógio; um jogo de pesca sem calma é um caça-níquel. O gênero vive no meio.

O design do minigame de fisgada

O minigame é onde o jogador ganha ou perde o peixe, então é onde a habilidade entra no loop. O padrão que eu recomendo pra um primeiro projeto tem duas fases.

Fase 1, a janela de timing. Depois do lançamento, um tempo de espera aleatório (dois a seis segundos funciona bem). Quando o peixe morde, abre uma janela curta pra apertar o botão, algo entre 0,5 e 1 segundo. Curta demais frustra, longa demais vira formalidade. O essencial é o feedback: um som seco, a boia afundando, um sinal visual impossível de não ver. O jogador tem que saber, sem dúvida nenhuma, que aquele é o momento.

Fase 2, a barra de tensão. Fisgou, começa o cabo de guerra. Segurar o botão puxa a linha e sobe a tensão; soltar alivia e desce. O peixe puxa por conta própria, em rajadas, com força que depende da raridade. O objetivo é manter a tensão numa zona segura: dentro dela, uma barra de progresso enche; tensão no máximo, a linha arrebenta; progresso zerado, o peixe escapa. Duas barras na tela, uma decisão por frame (segurar ou soltar), e a raridade do peixe vira dificuldade de forma natural, porque peixe mais forte empurra a tensão com mais violência.

O feedback é metade do minigame. A barra de tensão deve mudar de cor perto do limite, o controle deve vibrar (ou a tela tremer) nas rajadas do peixe, e o som da linha esticando é o aviso mais eficiente que existe. O jogador deve sentir o perigo antes de ler a barra.

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

Implementação na Godot 4: o minigame em GDScript tipado

Pra esse tipo de jogo 2D, com Timers, sinais e Resources fazendo o trabalho pesado, o Godot é a minha recomendação sem esforço; se você ainda está decidindo engine, a comparação completa entre Godot e Unity explica o porquê. Vamos ao código, tudo em GDScript com tipagem estática.

Primeiro, os dados do peixe como Resource. Cada espécie vira um arquivo .tres no editor, sem tocar em código:

class_name PeixeData
extends Resource

@export var nome: String = ""
@export var raridade: String = "comum"
@export var forca_min: float = 8.0
@export var forca_max: float = 18.0
@export var valor_venda: int = 10

Agora a fase 1, a janela de fisgada. Dois nós Timer como filhos (TimerEspera e TimerJanela, ambos com one_shot ativado) e uma ação de input chamada fisgar no Input Map:

class_name EsperaFisgada
extends Node

signal fisgada_disponivel
signal janela_perdida
signal fisgada_confirmada

const JANELA_SEGUNDOS: float = 0.6

@onready var timer_espera: Timer = $TimerEspera
@onready var timer_janela: Timer = $TimerJanela

var janela_aberta: bool = false

func _ready() -> void:
    timer_espera.timeout.connect(_abrir_janela)
    timer_janela.timeout.connect(_fechar_janela)

func lancar_linha() -> void:
    janela_aberta = false
    timer_espera.start(randf_range(2.0, 6.0))

func _abrir_janela() -> void:
    janela_aberta = true
    fisgada_disponivel.emit()
    timer_janela.start(JANELA_SEGUNDOS)

func _fechar_janela() -> void:
    janela_aberta = false
    janela_perdida.emit()

func _unhandled_input(event: InputEvent) -> void:
    if event.is_action_pressed("fisgar") and janela_aberta:
        janela_aberta = false
        timer_janela.stop()
        fisgada_confirmada.emit()

O sinal fisgada_disponivel é onde você pendura o feedback: som, animação da boia, tremida de tela. E fisgada_confirmada dispara a fase 2, o minigame de tensão. Ele precisa de um Timer filho chamado TimerComportamento, que alterna o peixe entre puxar e descansar:

class_name MinigamePesca
extends Node

signal peixe_capturado(peixe: PeixeData)
signal linha_arrebentou
signal peixe_escapou

const TENSAO_MAX: float = 100.0
const ZONA_MIN: float = 35.0
const ZONA_MAX: float = 75.0
const PUXAO_JOGADOR: float = 40.0
const ALIVIO_LINHA: float = 25.0
const GANHO_PROGRESSO: float = 20.0
const PERDA_PROGRESSO: float = 12.0

@onready var timer_comportamento: Timer = $TimerComportamento

var tensao: float = 50.0
var progresso: float = 25.0
var forca_peixe: float = 0.0
var peixe_puxando: bool = false
var ativo: bool = false
var peixe_atual: PeixeData = null

func _ready() -> void:
    timer_comportamento.timeout.connect(_alternar_comportamento)

func iniciar(peixe: PeixeData) -> void:
    peixe_atual = peixe
    forca_peixe = randf_range(peixe.forca_min, peixe.forca_max)
    tensao = 50.0
    progresso = 25.0
    peixe_puxando = false
    ativo = true
    _alternar_comportamento()

func _physics_process(delta: float) -> void:
    if not ativo:
        return

    if Input.is_action_pressed("fisgar"):
        tensao += PUXAO_JOGADOR * delta
    else:
        tensao -= ALIVIO_LINHA * delta

    if peixe_puxando:
        tensao += forca_peixe * delta

    tensao = clampf(tensao, 0.0, TENSAO_MAX)

    if tensao >= TENSAO_MAX:
        _encerrar()
        linha_arrebentou.emit()
        return

    if tensao >= ZONA_MIN and tensao <= ZONA_MAX:
        progresso += GANHO_PROGRESSO * delta
    else:
        progresso -= PERDA_PROGRESSO * delta

    if progresso >= 100.0:
        _encerrar()
        peixe_capturado.emit(peixe_atual)
    elif progresso <= 0.0:
        _encerrar()
        peixe_escapou.emit()

func _alternar_comportamento() -> void:
    peixe_puxando = not peixe_puxando
    timer_comportamento.start(randf_range(0.4, 1.2))

func _encerrar() -> void:
    ativo = false
    timer_comportamento.stop()

Isso é um minigame funcional. As variáveis tensao e progresso alimentam duas ProgressBar na UI, e os três sinais de saída conectam o resultado ao resto do jogo: peixe_capturado vai pro inventário e pra coleção, os outros dois vão pro feedback de derrota. Repare que a dificuldade inteira mora em forca_peixe: um peixe lendário com força 50 empurra a tensão pra fora da zona muito mais rápido que um comum com força 10, e você não escreveu uma linha de código de dificuldade.

A tabela de raridade

Falta decidir qual peixe morde. Uma tabela de pesos resolve, e dá pra escrever com um Array tipado de dicionários:

class_name TabelaPesca
extends Node

const TABELA_RARIDADE: Array[Dictionary] = [
    {"raridade": "comum", "peso": 60, "forca_min": 8.0, "forca_max": 18.0, "valor": 10},
    {"raridade": "incomum", "peso": 25, "forca_min": 15.0, "forca_max": 28.0, "valor": 30},
    {"raridade": "raro", "peso": 12, "forca_min": 25.0, "forca_max": 40.0, "valor": 90},
    {"raridade": "lendario", "peso": 3, "forca_min": 38.0, "forca_max": 55.0, "valor": 400},
]

func sortear_raridade() -> Dictionary:
    var peso_total: int = 0
    for entrada: Dictionary in TABELA_RARIDADE:
        peso_total += entrada["peso"] as int

    var sorteio: int = randi_range(1, peso_total)
    var acumulado: int = 0
    for entrada: Dictionary in TABELA_RARIDADE:
        acumulado += entrada["peso"] as int
        if sorteio <= acumulado:
            return entrada

    return TABELA_RARIDADE[0]

Com os pesos acima, 60% das mordidas são comuns e 3% são lendárias. O sorteio devolve a faixa de força e o valor, e você usa isso pra escolher (ou gerar) o PeixeData que entra no iniciar() do minigame. Quando o jogo crescer, essa tabela vira uma por bioma ou por horário, e a estrutura não muda: só o conteúdo do Array.

Repare como as três peças se conectam por sinal: a janela confirma a fisgada, a tabela sorteia o peixe, o minigame decide o resultado. Cada script tem uma responsabilidade e dá pra testar isoladamente, que é exatamente o que você quer num projeto solo.

Escopo mínimo viável: o que cortar no primeiro jogo

Depois de vinte e tantos anos vendo projetos morrerem de escopo, meu conselho pra um primeiro jogo de pesca é agressivo. Fica no jogo: um cenário (um lago, um píer, uma praia), o loop completo com as duas fases do minigame, 10 a 15 espécies em três ou quatro raridades, uma vara com dois upgrades comprados com o dinheiro da venda e uma tela de coleção com silhuetas. Isso é um jogo inteiro, terminável em poucos meses.

Fica de fora, sem culpa: barco e navegação (Dredge é outro orçamento), multiplayer (Webfishing parece simples e não é), clima e ciclo de dia afetando o spawn (multiplicador de balanceamento que triplica o teste), aquário decorável, culinária com os peixes e história com NPCs. Nenhum desses sistemas participa do loop de lançar, fisgar e coletar. Todos são expansões legítimas pra depois que a fundação estiver de pé e divertida.

O teste final é simples: se lançar a linha, vencer a tensão e ver a silhueta virar peixe na coleção já der aquela vontade de lançar de novo, você tem um jogo. Se não der, nenhum bioma extra vai salvar. A calma e a surpresa precisam estar no loop nu. O resto é decoração.

Perguntas frequentes

Como funciona a mecânica de pesca em jogos?

Quase todo jogo de pesca segue o mesmo loop de quatro passos: lançar a linha, esperar até o peixe morder, vencer um minigame curto de fisgada e coletar ou vender o que veio. A espera cria tensão, o minigame cria habilidade e a coleta cria progressão. A variação entre jogos está em qual desses passos recebe mais peso: Stardew Valley aposta no minigame de precisão, Dredge aposta no que vem na linha, Webfishing aposta no social ao redor da espera.

Qual engine usar pra fazer um jogo de pesca?

O Godot 4 é uma escolha excelente, principalmente em 2D. O gênero pede pouca coisa da engine: Timers pra janela de fisgada, um script de física simples pra barra de tensão, Resources pra dados de peixe e sinais pra conectar o minigame ao inventário. Tudo isso é nativo no Godot, gratuito e leve. Unity também resolve, mas pra um projeto solo desse escopo o Godot tira menos do seu caminho.

Como fazer o minigame de fisgada?

O padrão mais comum tem duas partes. Primeiro uma janela de timing: um Timer com espera aleatória seguido de uma janela curta, algo entre meio segundo e um segundo, em que o jogador precisa apertar o botão. Depois uma barra de tensão: segurar o botão sobe a barra, soltar desce, e o peixe puxa com força aleatória. Manter a tensão numa zona segura enche o progresso; estourar o limite arrebenta a linha. São duas barras e dois Timers, e o resto é ajuste de números.

Por que jogos de pesca fazem tanto sucesso?

Porque o loop combina calma com surpresa, uma mistura rara. A espera é relaxante e de baixa exigência, o que encaixa no apetite atual por jogos cozy. Mas cada lançamento é uma caixa fechada: pode vir um peixe comum, um raro ou algo estranho. Essa incerteza barata de produzir mantém o jogador lançando a linha de novo. Dredge provou que dá pra torcer o gênero pro horror e Webfishing provou que ele funciona como espaço social.

Quanto conteúdo um jogo de pesca precisa?

Menos do que parece. Um primeiro jogo fecha bem com um único cenário, entre 10 e 15 espécies distribuídas em três ou quatro raridades, uma vara com dois ou três upgrades e uma coleção que registra o que já foi pescado. Isso já sustenta algumas horas de jogo. Biomas, clima, horário do dia e aquário são multiplicadores ótimos, mas cada um deles multiplica também o custo de arte e de balanceamento. Deixe pra versão dois.