Godot do Zero: Câmera 2D com Camera2D e limites de fase

Capítulo 11

Tempo estimado de leitura: 10 minutos

+ Exercício

O que a Camera2D faz e por que usar limites

A Camera2D é o nó responsável por definir qual parte do mundo 2D será exibida na tela. Em um jogo com personagem controlável, o padrão é a câmera seguir o player para mantê-lo visível e centralizado. Sem configuração, isso pode gerar problemas comuns: “tremedeira” (jitter) ao seguir o corpo físico, câmera mostrando áreas fora da fase e sensação de movimento “duro” sem suavização.

Neste capítulo você vai: adicionar uma Camera2D ao player, configurar smoothing (suavização), definir limites de fase (limit_left/right/top/bottom), ajustar zoom, criar uma área de confinamento por sala/fase e adaptar a câmera para diferentes resoluções sem quebrar o enquadramento.

1) Adicionando Camera2D ao Player

Estrutura recomendada

Dentro da cena do player (por exemplo, um CharacterBody2D), adicione um nó filho Camera2D. Isso garante que a câmera acompanhe a posição do player automaticamente.

  • No player, adicione: Camera2D
  • Marque Enabled (Godot 4) para a câmera ficar ativa
  • Se houver mais de uma câmera na cena, garanta que apenas uma esteja habilitada por vez

Centralização e offset

Por padrão, a câmera centraliza no seu próprio global_position. Como ela é filha do player, ela seguirá o player. Se você quiser enquadrar um pouco “à frente” (ex.: em jogos de corrida), use offset. Para jogos de plataforma, normalmente deixe offset em (0, 0) para manter o player centralizado.

2) Suavização (Smoothing) para evitar movimento duro

O smoothing faz a câmera “atrasar” levemente e interpolar o movimento, deixando a sensação mais natural. Na Godot 4, a Camera2D possui opções de suavização que podem variar por versão, mas a ideia é a mesma: habilitar suavização e ajustar a velocidade.

Continue em nosso aplicativo e ...
  • Ouça o áudio com a tela desligada
  • Ganhe Certificado após a conclusão
  • + de 5000 cursos para você explorar!
ou continue lendo abaixo...
Download App

Baixar o aplicativo

Configuração prática

  • Ative Position Smoothing (ou propriedade equivalente)
  • Ajuste o valor de Smoothing Speed (ex.: 5 a 12) até ficar agradável

Se você notar jitter, o problema geralmente não é “falta de smoothing”, e sim descompasso entre física e renderização. Uma prática comum é garantir que o movimento do player aconteça no passo de física e que a câmera acompanhe de forma consistente (a câmera como filha do player já ajuda). Em casos mais chatos, você pode experimentar ativar o modo de processo apropriado da câmera (quando disponível) para acompanhar no mesmo ritmo do movimento.

3) Limites da câmera (limit_left/right/top/bottom)

Os limites impedem a câmera de mostrar fora da área jogável. Isso é essencial em fases com bordas definidas (TileMap, paredes, etc.).

Como pensar os limites

Os limites são valores em coordenadas do mundo (pixels/unidades 2D) que restringem o centro da câmera. Em geral, você define:

  • limit_left: menor X permitido
  • limit_right: maior X permitido
  • limit_top: menor Y permitido
  • limit_bottom: maior Y permitido

Esses valores devem corresponder ao retângulo interno da fase (ou sala) onde a câmera pode se mover.

Definindo limites manualmente (rápido para testar)

No Inspector da Camera2D, procure a seção de limites e preencha valores. Exemplo (fase 2000x1000 começando em (0,0)):

limit_left = 0
limit_top = 0
limit_right = 2000
limit_bottom = 1000

Se sua fase começa em outra posição (ex.: sala deslocada), use as coordenadas reais do mundo.

4) Zoom: aproximar/afastar sem distorcer o jogo

O zoom da Camera2D altera a escala da visão. Valores menores aproximam (ex.: (0.8, 0.8)), valores maiores afastam (ex.: (1.2, 1.2)).

Boas práticas

  • Mantenha zoom.x e zoom.y iguais para não “esticar”
  • Se você usa pixel art, combine zoom com configurações de projeto para evitar blur (filtro) e garantir pixels nítidos
  • Ao mudar o zoom, os limites continuam em coordenadas do mundo, mas a área visível muda; teste bordas para não revelar fora da fase

5) Área de confinamento por fase/sala (limites dinâmicos)

Em jogos com múltiplas salas, é comum cada sala ter seus próprios limites. Em vez de setar limites fixos na câmera, você pode criar uma “área de câmera” por sala e, quando o player entra nela, atualizar os limites da câmera automaticamente.

Abordagem recomendada: CameraBounds com Area2D

Crie um nó por sala chamado, por exemplo, CameraBounds, contendo um Area2D com um CollisionShape2D retangular cobrindo a sala. Quando o player entrar, a câmera passa a usar aquele retângulo como limites.

Passo a passo

  • Na cena da fase, crie Area2D (nome: CameraBounds)
  • Adicione CollisionShape2D com RectangleShape2D
  • Ajuste o retângulo para cobrir a área jogável da sala
  • Configure a camada/máscara para detectar o player (sem interferir em colisão física; é apenas detecção)

Script para aplicar limites ao entrar

Anexe este script ao CameraBounds. Ele calcula os limites com base no retângulo do CollisionShape2D e aplica na câmera do player.

extends Area2D

@export var camera_path: NodePath
@onready var shape := $CollisionShape2D.shape as RectangleShape2D

func _ready() -> void:
	body_entered.connect(_on_body_entered)

func _on_body_entered(body: Node) -> void:
	if not body.is_in_group("player"):
		return
	var cam := get_node_or_null(camera_path) as Camera2D
	if cam == null:
		# Alternativa: pegar a câmera como filha do player
		cam = body.get_node_or_null("Camera2D") as Camera2D
	if cam == null:
		return

	# Retângulo do bounds em coordenadas globais
	var half := shape.size * 0.5
	var center := global_position
	var left := int(center.x - half.x)
	var right := int(center.x + half.x)
	var top := int(center.y - half.y)
	var bottom := int(center.y + half.y)

	cam.limit_left = left
	cam.limit_right = right
	cam.limit_top = top
	cam.limit_bottom = bottom

Importante: para o exemplo acima funcionar, você precisa de uma forma consistente de achar a câmera. Duas opções simples:

  • Definir camera_path apontando para a Camera2D do player (ou uma câmera global)
  • Garantir que a câmera se chame Camera2D e seja filha do player

Como garantir transição suave entre salas

Ao trocar limites, a câmera pode “pular” se o player estiver perto da borda. Para suavizar:

  • Mantenha o smoothing ativo
  • Evite trocar limites a cada frame; troque apenas em eventos (entrada/saída)
  • Se duas áreas se sobrepõem, defina uma prioridade (ex.: sala atual vence) para não ficar alternando

6) Ajustando a câmera para diferentes resoluções (sem quebrar o enquadramento)

O objetivo é manter uma área de jogo consistente em diferentes telas. Você pode fazer isso combinando: (1) configurações de janela/viewport do projeto e (2) zoom controlado.

Estratégia prática: “resolução base” + zoom adaptativo

Defina uma resolução base (ex.: 320x180, 640x360, 1280x720) e calcule um zoom para caber na tela real mantendo proporção. Assim você preserva o campo de visão e evita que telas maiores mostrem “mais fase” do que o planejado.

Exemplo: script no player (ou em um nó gerenciador) para ajustar o zoom da câmera com base no tamanho da janela, mantendo a proporção da resolução base:

@export var base_resolution := Vector2(640, 360)
@onready var cam := $Camera2D

func _ready() -> void:
	_update_camera_zoom()
	get_viewport().size_changed.connect(_update_camera_zoom)

func _update_camera_zoom() -> void:
	var viewport_size := get_viewport().get_visible_rect().size
	var scale_x := viewport_size.x / base_resolution.x
	var scale_y := viewport_size.y / base_resolution.y
	var scale := min(scale_x, scale_y)
	# zoom maior = mais afastado; aqui queremos “encaixar” a base
	# então usamos o inverso do scale
	var z := 1.0 / max(scale, 0.001)
	cam.zoom = Vector2(z, z)

Com isso, você mantém o mesmo “enquadramento lógico” em diferentes resoluções. Teste em janelas com proporções diferentes (16:9, 16:10, ultrawide) e decida se prefere cortar (letterbox) ou mostrar mais cenário; o zoom adaptativo acima tende a preservar a área base, podendo sobrar espaço em uma dimensão dependendo do modo de estiramento do projeto.

7) Evitando jitter (tremedeira) ao manter o player centralizado

Jitter costuma aparecer quando o player se move em passos de física e a câmera tenta seguir em passos diferentes, ou quando há arredondamento/escala fracionária (especialmente com pixel art). Checklist rápido:

  • Deixe a câmera como filha do player (reduz discrepâncias)
  • Use smoothing moderado (nem 0, nem exagerado)
  • Evite zoom fracionário em pixel art se estiver causando tremulação; prefira valores que resultem em pixels inteiros na tela (dependendo do seu setup)
  • Se estiver usando TileMap/pixel art, revise configurações de filtro e snapping do projeto para evitar blur e subpixel

Exercício: duas salas com transição de câmera (atualizando limites)

Objetivo

Criar duas salas lado a lado. Ao atravessar a porta/corredor, a câmera deve atualizar os limites para a sala atual, mantendo o player centralizado e sem jitter perceptível.

Requisitos do exercício

  • Duas áreas retangulares (Sala A e Sala B) com tamanhos diferentes
  • Cada sala tem um CameraBounds (Area2D + CollisionShape2D retangular)
  • Ao entrar na sala, atualizar limit_left/right/top/bottom da câmera
  • Smoothing ligado para transição suave
  • Player permanece centralizado na maior parte do tempo (exceto quando encostado nos limites)

Passo a passo sugerido

  • Monte a Sala A e Sala B no mesmo mundo (por exemplo, Sala B à direita da Sala A)
  • Crie um corredor/porta entre elas (pode ser apenas um espaço livre)
  • Adicione CameraBounds na Sala A cobrindo sua área jogável
  • Adicione CameraBounds na Sala B cobrindo sua área jogável
  • Garanta que o player esteja no grupo player (Inspector > Node > Groups)
  • Em cada CameraBounds, configure camera_path para apontar para a Camera2D do player (ou deixe vazio e use a busca por filho Camera2D)
  • Ative smoothing na câmera e ajuste a velocidade
  • Teste atravessando de A para B e de B para A

Desafio extra (para eliminar alternância em áreas próximas)

Se a porta for estreita e as áreas encostarem, você pode entrar e sair rapidamente do Area2D, causando troca repetida de limites. Resolva adicionando prioridade:

  • Adicione @export var priority := 0 em cada CameraBounds
  • No player, mantenha a referência do bounds atual e só aceite trocar se a prioridade for maior (ou se o atual for nulo)

Exemplo de lógica no player (opcional):

# No Player.gd
var current_bounds_priority := -999

func apply_camera_limits(cam: Camera2D, left: int, right: int, top: int, bottom: int, priority: int) -> void:
	if priority < current_bounds_priority:
		return
	current_bounds_priority = priority
	cam.limit_left = left
	cam.limit_right = right
	cam.limit_top = top
	cam.limit_bottom = bottom

Daí o CameraBounds chamaria apply_camera_limits ao invés de setar direto. Isso evita “piscar” de limites quando duas áreas competem.

Agora responda o exercício sobre o conteúdo:

Ao implementar limites dinâmicos de câmera por sala usando uma Area2D com CollisionShape2D retangular, qual prática ajuda a evitar que a câmera fique alternando limites repetidamente na transição entre duas salas próximas?

Você acertou! Parabéns, agora siga para a próxima página

Você errou! Tente novamente.

Atualizar limites apenas quando o player entra/sai evita mudanças contínuas. Se duas áreas competirem (sobreposição/porta estreita), uma prioridade impede alternância de limites e reduz “pulos”, especialmente com smoothing ativo.

Próximo capitúlo

Godot do Zero: Interface do usuário (UI) básica com Control e CanvasLayer

Arrow Right Icon
Capa do Ebook gratuito Godot do Zero: Criando seu Primeiro Jogo 2D com GDScript
65%

Godot do Zero: Criando seu Primeiro Jogo 2D com GDScript

Novo curso

17 páginas

Baixe o app para ganhar Certificação grátis e ouvir os cursos em background, mesmo com a tela desligada.