Voltar para o Blog
Quest Log

Como Fazer um Jogo de Futebol: do Escopo ao Primeiro Gol na Godot

Partida de futebol em pixel art vista de cima, com jogadores de dois times disputando a bola numa arena fechada com um gol de cada lado

Como fazer um jogo de futebol de verdade: escopo arcade, física da bola na Godot, troca de jogador, IA de posicionamento e código GDScript tipado.

Como Fazer um Jogo de Futebol: do Escopo ao Primeiro Gol na Godot

Todo dev brasileiro pensa nisso em algum momento: como fazer um jogo de futebol. Eu penso nisso desde a era do Sensible Soccer, e em mais de vinte anos de indústria vi esse projeto específico quebrar mais gente do que quase qualquer outro, sempre pelo mesmo motivo: a régua mental é o FIFA. A pessoa abre a engine, percebe o tamanho do buraco entre o que imaginou e o que consegue construir, e desiste na segunda semana. Este guia existe pra evitar esse fim. Vou mostrar o recorte de escopo que funciona, os quatro problemas técnicos que todo jogo de futebol precisa resolver e código GDScript tipado, com API real da Godot 4, pra você sair daqui com um caminho concreto até o primeiro gol jogável.

Simulação ou arcade: decida antes de abrir a engine

Essa é a decisão que define tudo que vem depois, e ela precisa ser tomada antes de qualquer linha de código.

Simulação é o território do EA Sports FC e do eFootball: onze contra onze, táticas, impedimento, faltas, licenças de clubes e jogadores reais. É trabalho de estúdio grande, com equipes enormes e anos de produção contínua. Não é um julgamento sobre a sua capacidade, é aritmética de escopo: só a IA tática de vinte e dois jogadores em campo já é um problema que ocupa times inteiros de engenheiros. Pra um dev solo ou uma dupla, esse caminho não fecha a conta.

O caminho realista é o arcade, e a boa notícia é que ele tem tradição riquíssima. Três formatos funcionam muito bem pra indie:

Top-down 2D, na linha de Sensible Soccer e Pixel Cup Soccer: visão de cima, partidas curtas, times pequenos, controles de dois ou três botões. É o formato que eu recomendo pra começar, porque escala bem: você começa com 3x3 e cresce se fizer sentido.

Futebol de botão digital: por turnos, física de discos deslizando, nostalgia direta pra qualquer brasileiro que cresceu apertando botão na mesa de vidro. Elimina a IA em tempo real, que é a parte mais difícil do gênero, porque o adversário também joga por turnos.

1x1 estilo Head Soccer: dois personagens, um gol de cada lado, física exagerada e proposital. É o menor escopo possível que ainda entrega a fantasia de futebol, e cabe até em game jam.

O erro clássico é não decidir. A pessoa começa um arcade e vai enxertando regra de simulação: impedimento, escanteio, substituição, cartão. Cada regra dessas puxa sistemas inteiros atrás dela. Arcade bom não é simulação incompleta, é outro jogo, com outra proposta: ritmo, exagero e leitura instantânea. Sensible Soccer não tem impedimento e ninguém nunca sentiu falta.

Como fazer um jogo de futebol na prática: os quatro problemas centrais

Escolhido o formato, todo jogo de futebol em tempo real precisa resolver quatro problemas: a física da bola, a troca de jogador controlado, o posicionamento dos companheiros e os estados da partida. Vou passar por cada um com a solução que eu usaria hoje na Godot 4.

1. A física da bola: arcade é mais controlável

A tentação de todo dev é fazer a bola com RigidBody2D e deixar a engine simular tudo. Eu já caí nessa. O resultado é uma bola sabonete: quica de forma imprevisível, o passe nunca chega onde o jogador espera e cada ajuste de massa ou atrito muda três comportamentos ao mesmo tempo. Física realista dá autenticidade a um jogo de sinuca. Num futebol arcade, ela rouba de você a ferramenta mais importante que existe: a previsibilidade.

A solução arcade é fazer a bola como CharacterBody2D e controlar a velocidade na mão. O atrito é você quem aplica, o rebote na parede é você quem calcula, o chute define a velocidade diretamente. Cada comportamento fica isolado num número que você ajusta sem efeito colateral. Area2D entra como apoio: uma pra detectar a bola entrando no gol, outra no jogador pra saber quando a bola está no alcance do chute. Se a diferença entre esses corpos físicos ainda não está clara pra você, o guia de física de jogos no Godot explica quando usar cada um.

A bola inteira, com chute, atrito e rebote, cabe nisso:

extends CharacterBody2D
class_name Bola

@export var atrito: float = 600.0
@export var forca_maxima: float = 900.0

func chutar(direcao: Vector2, forca: float) -> void:
    velocity = direcao.normalized() * minf(forca, forca_maxima)

func _physics_process(delta: float) -> void:
    velocity = velocity.move_toward(Vector2.ZERO, atrito * delta)
    var colisao: KinematicCollision2D = move_and_collide(velocity * delta)
    if colisao:
        velocity = velocity.bounce(colisao.get_normal()) * 0.7

O move_toward freia a bola de forma constante, o que dá aquela rolada gostosa que desacelera até parar. O bounce no rebote, multiplicado por 0.7, faz a bola perder energia a cada quicada na parede da arena. E o chutar recebe direção e força separadas, o que abre espaço pra evoluir depois: chute fraco segurando pouco o botão, chute forte segurando mais, sem tocar no resto do código.

2. Trocar o jogador controlado

Num time com mais de um jogador, alguém precisa decidir quem o jogador humano controla agora. A regra clássica do gênero, que funciona desde os anos de Mega Drive: o controle vai pro jogador do time mais próximo da bola.

func jogador_mais_proximo_da_bola() -> Jogador:
    var escolhido: Jogador = null
    var menor_distancia: float = INF
    for filho in jogadores.get_children():
        var jogador := filho as Jogador
        if jogador == null:
            continue
        var distancia: float = jogador.global_position.distance_squared_to(bola.global_position)
        if distancia < menor_distancia:
            menor_distancia = distancia
            escolhido = jogador
    return escolhido

func trocar_controle() -> void:
    var novo: Jogador = jogador_mais_proximo_da_bola()
    if novo == jogador_ativo or novo == null:
        return
    if jogador_ativo:
        jogador_ativo.controlado = false
    jogador_ativo = novo
    jogador_ativo.controlado = true

Dois detalhes que valem a pena. Primeiro, distance_squared_to em vez de distance_to: pra comparar distâncias não precisa da raiz quadrada, e num loop que roda com frequência isso é de graça. Segundo, e mais importante: não chame trocar_controle todo frame. Quando dois jogadores estão quase à mesma distância da bola, a troca automática fica pingando entre eles e o jogador humano perde a mão. Chame a troca no apertar de um botão dedicado, ou só quando o novo candidato estiver claramente mais perto que o atual. Essa margem de tolerância é a diferença entre um controle que obedece e um que briga com o jogador.

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

3. IA de posicionamento: zonas mais atração pela bola

Aqui mora o medo de todo mundo que pensa em fazer futebol: "vou ter que programar IA tática". Não vai. Pra um arcade, uma regra de duas partes gera comportamento surpreendentemente convincente: cada jogador tem uma posição-base no campo, a zona dele, e é atraído na direção da bola, com um limite de quanto pode se afastar da base.

extends CharacterBody2D
class_name Jogador

@export var bola: Bola
@export var posicao_base: Vector2
@export var peso_bola: float = 0.35
@export var raio_de_acao: float = 180.0
@export var velocidade: float = 220.0

var controlado: bool = false

func _physics_process(_delta: float) -> void:
    if controlado:
        return
    var desvio: Vector2 = (bola.global_position - posicao_base) * peso_bola
    var alvo: Vector2 = posicao_base + desvio.limit_length(raio_de_acao)
    if global_position.distance_to(alvo) > 8.0:
        velocity = global_position.direction_to(alvo) * velocidade
    else:
        velocity = Vector2.ZERO
    move_and_slide()

O peso_bola controla o quanto o jogador é doido pela bola: um zagueiro com peso baixo segura a posição, um atacante com peso alto persegue mais. O limit_length impede que o time inteiro vire uma nuvem de moscas em cima da bola, que é exatamente o que acontece num jogo de criança de seis anos, e o que acontece no seu jogo se você pular esse limite. A estrutura é a mesma de uma IA de inimigos que perseguem e patrulham: um alvo calculado por regra simples e movimento em direção a ele. Quando o movimento estiver funcionando e você quiser tirar aquela cara robótica de linha reta, steering behaviors para movimento natural é a evolução direta desse código: os jogadores passam a fazer curvas e desviar uns dos outros sem você reescrever a lógica de decisão.

4. Estados da partida

Futebol não é um fluxo contínuo, é uma máquina de estados. No mínimo: KICKOFF, com a bola no centro e os jogadores nas posições iniciais esperando o input de início; JOGO, o fluxo corrido onde tudo acima acontece; e GOL, que congela a disputa, roda a celebração, soma o placar e devolve pro KICKOFF. Um enum e uma variável de estado no script da partida resolvem, e cada estado decide o que processa e o que ignora: durante GOL, ninguém chuta e a bola não se move.

E a bola saindo pela lateral? Resposta honesta: no começo, não existe lateral. Feche a arena com paredes, estilo futebol de salão de videogame, e a bola quica de volta. Lateral e escanteio parecem detalhes, mas cada um puxa reposicionamento de todos os jogadores, animação de reposição e regras de posse. São dois estados inteiros a mais na máquina. O jogo é divertido sem eles, e a prova é que vários arcades clássicos de futebol fizeram exatamente essa escolha.

O corte de escopo que te leva até o fim

Meu conselho concreto pra primeira versão, e falo isso como quem já viu muito projeto de futebol morrer inchado:

  • Arena fechada, sem lateral, sem escanteio, sem impedimento
  • 3x3, sem goleiro dedicado no começo: o defensor com peso de bola baixo cumpre o papel
  • Um botão de chute, na direção que o jogador está olhando
  • Troca de controle pro mais próximo da bola, no apertar de botão
  • Placar e cronômetro, partida de três minutos, e nada mais

Isso é um jogo completo. Dá pra jogar, dá pra mostrar, dá pra testar com gente de verdade. Passe, drible, carrinho, goleiro de verdade, faltas: tudo isso entra depois, um de cada vez, se o núcleo divertir. Se o 3x3 de um botão não for divertido, nenhuma dessas camadas vai salvar, e é melhor descobrir isso na semana três do que no mês oito.

Gol precisa de festa

Uma dica de game feel que muda o jogo inteiro custando quase nada: celebre o gol. Gol que só incrementa o placar é anticlímax, e futebol é um jogo em que tudo existe pra esse momento. Três ingredientes: screen shake na câmera no instante em que a bola cruza a linha, um som forte e distinto, e uma pausa curta antes do reposicionamento, meio segundo em que o jogo respira e o jogador comemora. Na Godot, o shake é um deslocamento aleatório decrescente no offset da Camera2D, e a pausa é um Timer segurando a transição do estado GOL pro KICKOFF. Uma tarde de trabalho, e é a diferença entre um protótipo e um jogo que as pessoas pedem pra jogar de novo.

Por onde continuar

O jogo de futebol é um projeto de segundo ou terceiro jogo, não de primeiro, porque junta física, IA de múltiplos agentes e máquina de estados num pacote só. Se algum desses pilares ainda está frouxo, vale investir nele isoladamente antes: os links ao longo do texto cobrem física e IA em profundidade. E se você quer estruturar essa caminhada em vez de juntar peças soltas, eu escrevi sobre a melhor forma de aprender a fazer jogos com a visão de quem contratou e formou muito dev nesses anos, que é a mesma visão que guia o CursoGame.Dev.

Agora escolhe teu formato, fecha a arena e vai atrás do primeiro gol. O resto do campeonato se constrói depois.

Perguntas frequentes

Qual engine é melhor pra fazer um jogo de futebol?

Pra um jogo de futebol arcade em 2D, o Godot resolve muito bem. Ele tem CharacterBody2D pra movimentação dos jogadores e da bola, Area2D pra detectar gol e alcance de chute, e GDScript é rápido de iterar, o que importa num gênero em que o ajuste fino da física define o jogo. É gratuito e leve. Unity também dá conta, mas pra um primeiro projeto do gênero eu iria de Godot.

É difícil fazer um jogo de futebol?

É mais difícil que um jogo de plataforma, porque você lida com vários agentes ao mesmo tempo: a bola, o jogador controlado e os companheiros e adversários movidos por IA. Mas um arcade 3x3 em arena fechada é totalmente viável pra quem já fez um ou dois jogos pequenos. O erro não é a dificuldade técnica, é mirar em simulação completa no primeiro projeto.

Posso usar nomes de times e jogadores reais no meu jogo?

Não sem licença. Nomes, escudos e uniformes de clubes são marcas registradas, e a imagem de jogadores reais também é protegida. As licenças que o FIFA e o eFootball usam custam caro justamente por isso. O caminho pra indie é criar times e jogadores fictícios, o que ainda dá liberdade criativa: nomes de zoeira e escudos próprios costumam cair bem com o público.

Quanto tempo leva pra fazer um jogo de futebol?

Depende do recorte. Um protótipo jogável de arena fechada, 3x3, com chute e placar, sai em algumas semanas de trabalho consistente pra quem já conhece a engine. Um jogo arcade completo e polido, com menus, times e som, é conversa de meses. Simulação no nível de FIFA não entra na conta: é trabalho de estúdio grande, com anos de produção e equipe dedicada.

Devo usar RigidBody2D pra bola do meu jogo de futebol?

Na maioria dos casos, não. RigidBody2D entrega física realista, mas tira o controle das suas mãos: a bola quica de forma imprevisível e o passe nunca chega onde o jogador espera. Num jogo arcade, a bola como CharacterBody2D com velocidade controlada por código deixa você definir exatamente como o chute, o atrito e o rebote se comportam. Previsibilidade vale mais que realismo aqui.

Como funciona a troca de jogador controlado?

A regra clássica é passar o controle pro jogador do seu time mais próximo da bola, calculando a distância de cada um até ela e escolhendo a menor. O cuidado é evitar que o controle fique pulando entre dois jogadores a cada frame quando eles estão quase à mesma distância. Trocar apenas no apertar de um botão, como os grandes do gênero fazem, resolve isso de forma simples.