O que são cenas e nós (e por que isso muda sua forma de construir jogos)
Na Godot, um jogo 2D é construído como uma composição de cenas reutilizáveis, e cada cena é uma árvore de nós. Pense em cena como um “bloco” que você pode salvar, instanciar várias vezes e combinar com outros blocos. Pense em nó como uma peça com uma responsabilidade clara: desenhar um sprite, detectar colisão, tocar áudio, controlar movimento, organizar filhos, etc.
Essa abordagem favorece: reuso (um inimigo pode ser instanciado várias vezes), organização (cada nó faz uma coisa), e manutenção (alterar uma cena-base atualiza variações por herança).
Cena como “prefab”
Quando você salva uma cena (por exemplo, Player.tscn), ela vira um recurso que pode ser instanciado dentro de outras cenas. Isso é equivalente ao conceito de “prefab”: um modelo pronto para ser colocado no mundo quantas vezes você quiser.
Árvore de nós: hierarquia, responsabilidades e organização
Uma cena sempre tem um nó raiz e pode ter filhos, netos, etc. A hierarquia importa porque:
- Transformações 2D (posição, rotação, escala) são herdadas: mover o pai move os filhos.
- Organização lógica: agrupar nós relacionados (ex.:
PlayercomSprite2DeCollisionShape2D). - Ordem de desenho: em 2D, a ordem visual depende de camadas e/ou profundidade (mais abaixo).
Quando usar Node2D, CharacterBody2D, Area2D e CanvasLayer
| Tipo | Use quando… | Exemplo típico |
|---|---|---|
Node2D | Você precisa de transformações 2D (posição/rotação/escala), mas não precisa de física de personagem pronta. | Um marcador, um container de elementos, um inimigo estático, um spawner. |
CharacterBody2D | Você quer mover um personagem com colisão sólida e controle de movimento (ex.: move_and_slide()). | Jogador que anda e colide com paredes/chão. |
Area2D | Você quer detectar sobreposições (entrar/sair), gatilhos e hitboxes, sem ser um corpo sólido por padrão. | Hitbox de ataque, coletáveis, zona de dano, sensor de visão. |
CanvasLayer | Você quer UI/HUD desenhada acima do mundo, independente da câmera e da profundidade do cenário. | Barra de vida, pontuação, botões, overlay. |
Transformações 2D na prática (posição, rotação, escala)
Em nós 2D (como Node2D, CharacterBody2D, Area2D), você trabalha com propriedades como position, rotation e scale. Como a transformação é hierárquica, um Sprite2D filho “segue” o pai.
- Ouça o áudio com a tela desligada
- Ganhe Certificado após a conclusão
- + de 5000 cursos para você explorar!
Baixar o aplicativo
# Exemplo simples: mover um Node2D para a direita ao longo do tempo (em _process)extends Node2D
func _process(delta):
position.x += 100.0 * deltaEm personagens com física (como CharacterBody2D), o movimento normalmente é feito por velocidade e métodos de movimento, não alterando posição diretamente a cada frame.
Ordem de desenho (quem aparece na frente?)
Em 2D, a Godot pode ordenar o desenho por diferentes mecanismos. Os mais comuns:
- Z Index (em nós como
CanvasItem, ex.:Sprite2D): valores maiores desenham na frente. - Y Sort (quando você usa um nó apropriado para ordenar por Y): objetos “mais abaixo” (maior Y) podem aparecer na frente, útil para visão top-down.
- CanvasLayer: UI em uma camada separada, sempre acima/abaixo conforme a layer.
Regra prática: use CanvasLayer para HUD; use Z Index para ajustes pontuais; use ordenação por Y quando fizer sentido para profundidade “2.5D” em top-down.
Passo a passo: criando cenas reutilizáveis (Main, Player, Enemy)
1) Criar a cena do Player (Player.tscn)
Objetivo: um personagem controlável com colisão sólida.
- Crie uma nova cena com nó raiz
CharacterBody2De renomeie paraPlayer. - Adicione um
Sprite2Dcomo filho (para visual). - Adicione um
CollisionShape2Dcomo filho (para colisão). Configure uma forma (ex.:RectangleShape2D). - Anexe um script ao
Player(GDScript) para movimentação básica.
extends CharacterBody2D
@export var speed: float = 220.0
func _physics_process(delta):
var input_vector = Vector2(
Input.get_action_strength("ui_right") - Input.get_action_strength("ui_left"),
Input.get_action_strength("ui_down") - Input.get_action_strength("ui_up")
)
velocity = input_vector.normalized() * speed
move_and_slide()Observação: este exemplo usa ações padrão (ui_up, ui_down, etc.). Se você estiver usando ações personalizadas, ajuste os nomes.
Salve a cena como Player.tscn.
2) Criar a cena do Enemy (Enemy.tscn)
Objetivo: um inimigo simples com presença física (colisão) e uma área de detecção (sensor).
- Crie uma nova cena com nó raiz
Node2De renomeie paraEnemy. - Adicione um
Sprite2D(visual). - Para colisão sólida, você pode escolher duas abordagens:
- Abordagem A (mais simples para começar): manter como
Node2De usar apenasArea2Dpara detectar o player (sem colisão sólida). - Abordagem B (colisão sólida): trocar o nó raiz para
CharacterBody2DouRigidBody2D(dependendo do comportamento). Para este capítulo, foque na composição e mantenha o inimigo simples.
Vamos usar Node2D + Area2D para reforçar o papel de sensor:
- Adicione um
Area2Dcomo filho doEnemye renomeie paraDetectionArea. - Dentro de
DetectionArea, adicioneCollisionShape2De configure a forma (ex.: círculo). - Conecte o sinal
body_entereddoDetectionAreaao script doEnemy(ou faça via código).
extends Node2D
func _ready():
$DetectionArea.body_entered.connect(_on_detection_body_entered)
func _on_detection_body_entered(body):
if body.name == "Player":
print("Player detectado!")Salve a cena como Enemy.tscn.
3) Criar a cena principal (Main.tscn) e instanciar Player/Enemy
Objetivo: uma cena que compõe o jogo instanciando outras cenas.
- Crie uma nova cena com nó raiz
Node2De renomeie paraMain. - Crie um nó filho
Node2DchamadoWorld(onde ficam player/inimigos). - Crie um nó
CanvasLayerchamadoHUD(onde ficará UI). Dentro dele você pode adicionar umLabel(opcional) para testar. - No
Main, anexe um script para instanciar as cenas.
extends Node2D
@export var player_scene: PackedScene
@export var enemy_scene: PackedScene
func _ready():
var player = player_scene.instantiate()
$World.add_child(player)
player.position = Vector2(200, 200)
for i in 3:
var enemy = enemy_scene.instantiate()
$World.add_child(enemy)
enemy.position = Vector2(400 + i * 80, 220)Passo importante: no Inspector do Main, arraste Player.tscn para player_scene e Enemy.tscn para enemy_scene. Assim você evita caminhos hardcoded e mantém o projeto flexível.
Salvamento, instanciação e edição: fluxo de trabalho recomendado
- Crie uma cena pequena (ex.:
Player), teste isoladamente. - Salve como
.tscne trate como “prefab”. - Instancie em
Maine ajuste posições/quantidade. - Quando precisar de variações (ex.: inimigo rápido), use herança de cena.
Herança de cenas: criando variações sem duplicar trabalho
Herança de cena permite criar uma cena “filha” baseada em outra. Você reaproveita a estrutura e altera apenas o necessário (valores exportados, sprites, comportamento).
Passo a passo: Enemy base e EnemyFast
- Garanta que
Enemy.tscnseja sua base. - Crie uma nova cena a partir de
Enemy.tscnusando a opção de instanciar/derivar (criar cena herdada). - Salve como
EnemyFast.tscn. - No script, use variáveis exportadas para permitir variação sem reescrever lógica.
extends Node2D
@export var patrol_speed: float = 60.0
func _process(delta):
position.x += patrol_speed * deltaNa cena herdada EnemyFast.tscn, altere patrol_speed no Inspector (ex.: 120). Assim você cria variações mantendo a mesma base.
Agrupamento lógico: organizando e acessando conjuntos de nós
Além da hierarquia, você pode usar Groups para marcar nós por função (ex.: todos os inimigos). Isso facilita buscar e aplicar lógica em lote.
- Adicione o
Enemyao grupoenemies(via Inspector > Node > Groups). - No
Main, você pode encontrar todos os inimigos:
for e in get_tree().get_nodes_in_group("enemies"):
e.position.x += 10Exercícios práticos (para fixar composição com cenas)
Exercício 1: Estrutura mínima das cenas
- Player.tscn: raiz
CharacterBody2D+Sprite2D+CollisionShape2D. - Enemy.tscn: raiz
Node2D+Sprite2D+Area2D(comCollisionShape2D). - Main.tscn: raiz
Node2D+World(Node2D) +HUD(CanvasLayer).
Exercício 2: Instanciação mista (editor + código)
- Instancie o
Playermanualmente no editor dentro deWorld. - Instancie os
Enemypor código (loop) no_ready(). - Compare o fluxo: quando é mais prático instanciar no editor e quando é melhor por código?
Exercício 3: Herança de cena para variações
- Crie
EnemyFast.tscnherdando deEnemy.tscn. - Altere apenas um parâmetro exportado (velocidade, tamanho da área de detecção, cor/modulação do sprite).
- No
Main, instancie 2 inimigos normais e 1 rápido.
Exercício 4: Camadas e HUD com CanvasLayer
- Dentro de
HUD, adicione umLabelcom um texto de teste (ex.: “HP: 3”). - Mova o player e inimigos: confirme que o HUD permanece “por cima” e não se mistura com o mundo.
- Opcional: ajuste
layerdoCanvasLayerse você tiver múltiplas camadas de UI.