Como fazer um jogo de estratégia RTS na Godot 4

Como fazer um jogo de estratégia em tempo real (RTS) na Godot 4: seleção de unidades, pathfinding em grupo, comandos, coleta e IA de unidade.
Fazer um jogo de estratégia em tempo real assusta no começo, e com razão: um RTS junta vários sistemas que precisam conversar entre si. Mas quando você quebra o gênero em partes, cada peça é bem tratável. Neste guia sobre como fazer um jogo de estratégia RTS na Godot 4, vou destrinchar os sistemas essenciais de um jogo RTS: seleção de unidades, movimentação em grupo com pathfinding, comandos de mover e atacar, coleta de recursos, construção e uma IA básica de unidade com máquina de estados. Tudo com GDScript tipado e nós reais da engine.
A ideia não é entregar um jogo pronto, e sim mostrar como cada sistema encaixa. Comece em 2D, com poucas unidades, e vá somando peças.
Como fazer a seleção de unidades num jogo RTS
O primeiro sistema de qualquer RTS é a seleção. O jogador precisa clicar numa unidade ou arrastar uma caixa sobre várias. Vamos usar um nó gerenciador que escuta o mouse e guarda a lista de unidades selecionadas.
Cada unidade será um CharacterBody2D chamado Unit. O gerenciador registra onde o clique começou e, ao soltar, monta um Rect2 para saber quem ficou dentro.
extends Node2D
class_name SelectionManager
var inicio_arrasto: Vector2 = Vector2.ZERO
var arrastando: bool = false
var selecionadas: Array[Unit] = []
func _unhandled_input(evento: InputEvent) -> void:
if evento is InputEventMouseButton and evento.button_index == MOUSE_BUTTON_LEFT:
if evento.pressed:
inicio_arrasto = get_global_mouse_position()
arrastando = true
else:
finalizar_selecao(get_global_mouse_position())
arrastando = false
func finalizar_selecao(fim: Vector2) -> void:
var caixa: Rect2 = Rect2(inicio_arrasto, fim - inicio_arrasto).abs()
selecionadas.clear()
for unidade in get_tree().get_nodes_in_group("unidades"):
var u: Unit = unidade as Unit
if caixa.has_point(u.global_position):
selecionadas.append(u)
u.definir_selecionada(true)
else:
u.definir_selecionada(false)
O Rect2(...).abs() resolve o problema de arrastar da direita para a esquerda ou de baixo para cima, quando o tamanho fica negativo. Se a caixa for muito pequena (quase um clique), você trata como seleção de uma unidade só. Cada Unit guarda seu próprio estado de seleção e mostra um contorno quando definir_selecionada(true) é chamado.
Para desenhar a caixa na tela enquanto o jogador arrasta, use _draw() no gerenciador e chame queue_redraw() a cada movimento do mouse. É um retângulo semitransparente entre inicio_arrasto e a posição atual.
Movimentação em grupo com pathfinding
Com as unidades selecionadas, o jogador clica com o botão direito para mandá-las andar. Aqui entra o pathfinding, que calcula o caminho desviando de obstáculos. A Godot 4 faz isso com o NavigationAgent2D, que você adiciona como filho da unidade.
Você define um destino no agente, e ele devolve o próximo ponto do trajeto a cada frame. Sua função só precisa mover o corpo em direção a esse ponto.
extends CharacterBody2D
class_name Unit
@export var velocidade: float = 120.0
@onready var agente: NavigationAgent2D = $NavigationAgent2D
func mover_para(destino: Vector2) -> void:
agente.target_position = destino
func _physics_process(_delta: float) -> void:
if agente.is_navigation_finished():
velocity = Vector2.ZERO
return
var proximo: Vector2 = agente.get_next_path_position()
var direcao: Vector2 = global_position.direction_to(proximo)
velocity = direcao * velocidade
move_and_slide()
Para a movimentação em grupo funcionar, chame mover_para em cada unidade selecionada. Se você mandar todas para o mesmo ponto, elas vão se empilhar. Uma solução simples é espalhar os destinos numa pequena formação ao redor do clique, dando um deslocamento diferente para cada unidade. O NavigationAgent2D também tem avoidance_enabled, que ajuda as unidades a não se atravessarem.
Lembre que o pathfinding precisa de um NavigationRegion2D na cena, com um polígono de navegação desenhado sobre o terreno andável. Sem essa malha, o agente não tem por onde calcular caminho. Se você quer entender esse sistema a fundo, veja o guia de pathfinding com NavigationAgent2D na Godot, que cobre a configuração da região passo a passo.
Comandos: mover e atacar
O botão direito já serve para mover. Mas num RTS o mesmo clique pode virar um comando de ataque quando cai sobre um inimigo. O truque é checar o que está debaixo do cursor antes de decidir o comando.
Uma forma limpa é dar a cada unidade inimiga um Area2D e testar se o clique acertou algum. Se acertou, o comando é atacar aquele alvo; se não, é mover para o ponto do chão.
func processar_comando(pos_mouse: Vector2, alvo: Unit) -> void:
if alvo != null and alvo.time != time:
for u in selecionadas:
u.ordenar_ataque(alvo)
else:
for u in selecionadas:
u.mover_para(pos_mouse)
No lado da unidade, ordenar_ataque guarda a referência do alvo e troca o estado interno para perseguir e atacar. Enquanto o alvo estiver longe, a unidade caminha até ele usando o mesmo mover_para. Quando chega no alcance, para e dispara o ataque em intervalos, controlados por um Timer ou por um acumulador de tempo. Esse padrão de detectar alcance e disparar em ciclo é o mesmo de outros gêneros, como você vê em como fazer um jogo tower defense, onde torres também miram e atacam alvos que entram no raio.
Coleta de recursos e construção
Economia é o que separa um RTS de um jogo de batalha puro. O padrão clássico: uma unidade trabalhadora vai até um recurso (ouro, madeira, cristal), coleta uma quantidade, volta para uma base e deposita. O total fica num nó gerenciador de recursos.
extends Node
class_name GerenciadorRecursos
var ouro: int = 200
var madeira: int = 100
func pode_pagar(custo_ouro: int, custo_madeira: int) -> bool:
return ouro >= custo_ouro and madeira >= custo_madeira
func cobrar(custo_ouro: int, custo_madeira: int) -> void:
ouro -= custo_ouro
madeira -= custo_madeira
func depositar_ouro(quantidade: int) -> void:
ouro += quantidade
A construção usa esse gerenciador. Quando o jogador manda erguer um prédio, você chama pode_pagar para ver se há recursos, cobrar para descontar e então instancia a cena do edifício na posição escolhida. Vale mostrar uma prévia semitransparente que segue o mouse e só permite confirmar em terreno livre, checando colisão antes de fixar. Uma vez colocado, o prédio pode servir de ponto de depósito ou treinar novas unidades ao longo do tempo.
IA básica de unidade com máquina de estados
Cada unidade precisa de um cérebro simples que decide o que fazer sem esperar comando do jogador o tempo todo. A ferramenta certa aqui é a máquina de estados. Em vez de um monte de if aninhados, você define estados nomeados e regras de transição entre eles.
Para um soldado, três estados já dão um bom comportamento: PARADO, MOVENDO e ATACANDO. A unidade só executa a lógica do estado atual e troca de estado quando a situação muda.
enum Estado { PARADO, MOVENDO, ATACANDO }
var estado_atual: Estado = Estado.PARADO
var alvo: Unit = null
func _process(_delta: float) -> void:
match estado_atual:
Estado.PARADO:
var inimigo: Unit = procurar_inimigo_proximo()
if inimigo != null:
alvo = inimigo
estado_atual = Estado.ATACANDO
Estado.MOVENDO:
if agente.is_navigation_finished():
estado_atual = Estado.PARADO
Estado.ATACANDO:
if alvo == null or not is_instance_valid(alvo):
estado_atual = Estado.PARADO
elif global_position.distance_to(alvo.global_position) > alcance:
mover_para(alvo.global_position)
Cada estado tem uma responsabilidade clara. PARADO fica de olho em inimigos próximos e reage. MOVENDO só espera terminar o trajeto. ATACANDO mantém a distância certa e desfere golpes. Quando o alvo morre, a unidade volta para PARADO e recomeça o ciclo. Esse esqueleto cresce bem: dá para adicionar RECUANDO, PATRULHANDO ou SEGUINDO sem bagunçar o resto do código, porque cada estado é isolado.
Um detalhe importante: comandos do jogador têm prioridade sobre a IA. Se o jogador mandar a unidade recuar no meio de um combate, o comando deve forçar a troca de estado. Trate a ordem do jogador como um evento que sobrescreve a decisão automática.
Juntando os sistemas
Repare que nenhum desses sistemas é complicado sozinho. A seleção é geometria de retângulo. A movimentação é o NavigationAgent2D fazendo o trabalho pesado. Os comandos são um teste de "o que tem debaixo do mouse". A economia é aritmética num nó gerenciador. E a IA é uma máquina de estados com três caixas. O RTS nasce da forma como essas peças se conectam.
O caminho prático é construir na ordem em que você testa: primeiro seleção e movimento (dá para brincar já), depois comandos de ataque, depois economia e construção, e por fim a IA de unidade. Cada etapa é jogável, o que mantém o projeto motivador em vez de virar uma montanha de código sem retorno. Se você ainda está decidindo se o RTS é o gênero certo para o seu primeiro projeto grande, dá para comparar com opções mais enxutas no panorama de gêneros de jogos explicados.
Um RTS é um ótimo projeto para amadurecer como desenvolvedor porque exige arquitetura de verdade, não só scripts soltos. Se você quer aprender esses fundamentos de forma estruturada, do GDScript tipado à organização de cenas e sistemas, o curso da CursoGame.Dev leva você por esse caminho com projetos práticos. Nada de atalho mágico: é estudo e prática, mas com um roteiro claro em vez de tutoriais soltos que nunca se conectam.
Perguntas frequentes
Preciso saber programar para fazer um jogo RTS na Godot?
Sim, ao menos o básico de GDScript. Um RTS envolve seleção, pathfinding, comandos e IA, então você vai escrever bastante lógica. A boa notícia é que a Godot 4 já traz sistemas prontos como o NavigationAgent2D, que poupam muito trabalho.
Qual nó uso para movimentar as unidades do meu RTS?
Use CharacterBody2D para o corpo da unidade e NavigationAgent2D para calcular o caminho até o destino. O agente devolve o próximo ponto do trajeto e você move a unidade em direção a ele a cada frame físico.
Como faço a caixa de seleção (clique e arrasto)?
Guarde a posição do mouse quando o botão esquerdo é pressionado e a posição atual enquanto arrasta. Com esses dois pontos você monta um Rect2 e testa quais unidades caem dentro dele ao soltar o botão.
O que é uma máquina de estados na IA de unidade?
É uma forma de organizar o comportamento em estados como PARADO, MOVENDO e ATACANDO. A unidade só faz o que o estado atual permite e troca de estado quando algo muda, como um inimigo entrar no alcance. Isso evita código cheio de condições confusas.
Dá para fazer um RTS sozinho como iniciante?
Um RTS completo é ambicioso, mas você pode começar pequeno. Faça primeiro a seleção e a movimentação de poucas unidades, depois adicione comandos, coleta e IA aos poucos. Cada sistema funciona de forma independente e pode ser testado sozinho.
RTS em 2D ou 3D é melhor para começar?
Comece em 2D. A lógica de seleção, pathfinding e comandos é a mesma nos dois casos, mas o 2D tem menos variáveis de câmera, colisão e arte para gerenciar. Depois de dominar os sistemas você migra os conceitos para o 3D.


