projeto

Inimigos Simples: Movimento e Lógica Básica

Aprenda sobre inimigos simples: movimento e lógica básica

45 min
Aula 3 de 5

🤖 Inimigos Simples: Movimento e Lógica Básica

Bem-vindos à aula onde daremos vida aos nossos primeiros adversários! 😈 Nesta etapa do projeto, aprenderemos a criar inimigos simples que se movem e reagem de forma básica, adicionando um desafio crucial ao seu jogo 2D.

🎯 1. Introdução

Em qualquer jogo, os inimigos são elementos que testam as habilidades do jogador e tornam a experiência mais envolvente. Nesta aula, focaremos em inimigos com movimento e lógica básicos, ideais para iniciantes. Nosso objetivo é que você entenda como:

  • Configurar um nó de inimigo usando CharacterBody2D.
  • Implementar movimento linear (patrulha).
  • Adicionar lógica para mudar de direção.
  • Integrar animações simples.

Vamos construir um inimigo que patrulha uma área definida, virando-se quando atinge os limites. Este será o alicerce para inimigos mais complexos no futuro! 🚀

🚶‍♂️ 2. Explicação Detalhada: Criando Nosso Inimigo Patrulheiro

Para o nosso inimigo simples, utilizaremos o nó CharacterBody2D devido à sua capacidade de lidar com física e colisões de forma robusta e controlada por código, ideal para personagens (sejam eles jogadores ou inimigos).

2.1. Estrutura do Nó do Inimigo

Começaremos criando uma nova cena para o nosso inimigo.

  1. Nó Raiz: CharacterBody2D (renomeie para Enemy).
  2. Filhos Essenciais:
    • AnimatedSprite2D: Para exibir as animações do inimigo.
    • CollisionShape2D: Para definir a área de colisão física do inimigo. Escolha um RectangleShape2D ou CapsuleShape2D que se ajuste bem ao seu sprite.
    • Area2D (Opcional, mas recomendado para detecção de dano/jogador): Para detectar colisões de forma não-física (ex: o jogador entrou na área de ataque). Adicione um CollisionShape2D como filho.
    • Marker2D (Opcional, mas recomendado para pontos de patrulha): Pode ser útil para definir visualmente os limites ou pontos de patrulha no editor.
Enemy (CharacterBody2D)
├── AnimatedSprite2D
├── CollisionShape2D
├── Area2D (para detecção de jogador/dano)
│   └── CollisionShape2D
├── Marker2D (PatrolPointA)
└── Marker2D (PatrolPointB)

2.2. Configurando o AnimatedSprite2D

Certifique-se de ter sprites para o seu inimigo (pelo menos uma animação de "andando" ou "idle").

  1. Selecione o nó AnimatedSprite2D.
  2. No Inspector, crie um novo SpriteFrames no campo "Sprite Frames".
  3. Adicione animações (ex: "idle", "walk") e importe suas texturas.
  4. Defina a animação inicial para "walk" ou "idle".

2.3. Lógica de Movimento de Patrulha

Nosso inimigo patrulhará entre dois pontos. Usaremos variáveis para controlar a velocidade, a direção e os pontos de patrulha.

Vamos definir os pontos de patrulha usando as posições de dois Marker2D filhos do Enemy. Isso torna fácil ajustar os limites no editor.

# enemy.gd
extends CharacterBody2D
 
@export var speed: float = 50.0 # Velocidade do inimigo
@export var direction: int = 1 # 1 para direita, -1 para esquerda
 
@onready var animated_sprite: AnimatedSprite2D = $AnimatedSprite2D
@onready var patrol_point_a: Marker2D = $PatrolPointA
@onready var patrol_point_b: Marker2D = $PatrolPointB
 
var target_position: Vector2 # Onde o inimigo está se movendo atualmente
 
func _ready() -> void:
    # Define o primeiro ponto de patrulha como o ponto inicial
    target_position = patrol_point_a.global_position
    # Garante que a direção inicial esteja correta para o primeiro ponto
    if global_position.x > target_position.x:
        direction = -1
    else:
        direction = 1
    
    update_sprite_direction()
 
func _physics_process(delta: float) -> void:
    # Calcula a direção para o ponto alvo
    var move_direction: Vector2 = (target_position - global_position).normalized()
    
    # Move o inimigo
    velocity = move_direction * speed
    move_and_slide()
    
    # Verifica se o inimigo chegou perto do ponto alvo
    if global_position.distance_to(target_position) < 5: # Tolerância de 5 pixels
        # Se chegou ao ponto A, o próximo alvo é o B
        if target_position == patrol_point_a.global_position:
            target_position = patrol_point_b.global_position
        # Se chegou ao ponto B, o próximo alvo é o A
        else:
            target_position = patrol_point_a.global_position
        
        # Atualiza a direção visual (flip)
        update_sprite_direction()
 
func update_sprite_direction() -> void:
    # Calcula a direção baseada no ponto alvo
    if target_position.x < global_position.x:
        animated_sprite.flip_h = true # Vira para a esquerda
    else:
        animated_sprite.flip_h = false # Vira para a direita
    
    # Opcional: Iniciar animação de caminhada
    if animated_sprite.animation != "walk":
        animated_sprite.play("walk")
 

2.4. Melhores Práticas e Detalhes do Código

  • @export: Permite que você ajuste speed e a direction inicial diretamente no Inspector do Godot, sem precisar editar o código. Isso é excelente para balanceamento e testes!
  • @onready: Garante que os nós filhos (AnimatedSprite2D, PatrolPointA, PatrolPointB) sejam referenciados apenas quando estiverem prontos na árvore de cena, evitando erros.
  • _physics_process(delta): É a função ideal para lidar com a lógica de física e movimento. É chamada a uma taxa fixa, o que garante consistência no movimento independentemente da taxa de quadros.
  • move_and_slide(): É o método padrão para mover CharacterBody2Ds. Ele lida com colisões e deslizamento ao longo das superfícies.
  • normalized(): Retorna um vetor de comprimento 1 na mesma direção. Essencial para garantir que a velocidade seja consistente, independentemente da distância até o alvo.
  • global_position: Usamos global_position para os Marker2Ds porque suas posições no editor são relativas ao seu pai (Enemy), mas queremos as coordenadas absolutas no mundo para o cálculo da distância.
  • update_sprite_direction(): Uma função auxiliar para manter o código limpo e encapsular a lógica de virar o sprite e tocar a animação.

2.5. Configuração no Editor

  1. Crie uma nova cena Enemy.tscn.
  2. Adicione um CharacterBody2D como nó raiz. Renomeie para Enemy.
  3. Adicione AnimatedSprite2D, CollisionShape2D, PatrolPointA (Marker2D) e PatrolPointB (Marker2D) como filhos.
  4. Configure o AnimatedSprite2D com suas animações.
  5. Configure o CollisionShape2D para cobrir o sprite do inimigo.
  6. Posicione PatrolPointA e PatrolPointB. Estes nós são visíveis apenas no editor. Arraste-os para as posições onde você quer que o inimigo comece e termine sua patrulha. Eles devem ser filhos do Enemy para que suas posições sejam relativas ao inimigo, mas o script usa global_position para o cálculo no mundo.
  7. Anexe o script enemy.gd ao nó Enemy.
  8. Arraste sua cena Enemy.tscn para a cena principal do seu jogo para instanciar o inimigo.

🧪 3. Código de Exemplo Oficial (Adaptado)

O código acima é uma adaptação de práticas recomendadas da documentação oficial do Godot para CharacterBody2D e gerenciamento de estados simples. Embora não haja um exemplo "inimigo patrulheiro" direto, os princípios de movimento, _physics_process, move_and_slide, e uso de AnimatedSprite2D são diretamente extraídos de exemplos e guias oficiais.

Você pode encontrar mais informações sobre CharacterBody2D e movimento em:

🤝 4. Integração (Godot Engine)

A integração neste caso é a própria forma como o Godot funciona:

  • Nós e Cena: Os diferentes nós (CharacterBody2D, AnimatedSprite2D, CollisionShape2D, Marker2D) são conectados na árvore de cena para formar a entidade do inimigo.
  • Scripting: O GDScript (enemy.gd) é anexado ao nó raiz (Enemy) e controla o comportamento de todos os seus filhos, acessando-os via $NodeName.
  • Inspector: As propriedades @export são expostas no Inspector, permitindo a configuração visual do comportamento do inimigo sem tocar no código.

🏋️ 5. Exercícios/Desafios

Agora é a sua vez de colocar a mão na massa e expandir a lógica do nosso inimigo simples!

✅ Task List:

  • Implementar o Inimigo Patrulheiro: Siga os passos acima para criar a cena do inimigo (Enemy.tscn) e o script (enemy.gd). Instancie-o na sua cena principal e teste o movimento.
  • Ajustar Velocidade e Pontos de Patrulha: Use o Inspector para mudar a speed do inimigo. Arraste os Marker2Ds (PatrolPointA, PatrolPointB) para diferentes posições e observe como o comportamento do inimigo muda.
  • Animação de Idle: Adicione uma animação "idle" (parado) ao seu AnimatedSprite2D. Modifique o script para que o inimigo toque a animação "idle" quando estiver parado ou esperando (se você adicionar uma pausa).
  • Inimigo Vertical: Crie um novo inimigo que patrulha verticalmente (para cima e para baixo) em vez de horizontalmente. Você precisará ajustar a lógica de velocity e flip_h (talvez usando flip_v ou rotação, dependendo do seu sprite).
  • Pausa na Patrulha (Desafio Extra): Modifique o script para que o inimigo pause por alguns segundos (await get_tree().create_timer(tempo_pausa).timeout) cada vez que atingir um ponto de patrulha, antes de se virar e ir para o próximo.

🔚 6. Resumo e Próximos Passos

Nesta aula, você aprendeu a criar um inimigo básico com movimento de patrulha usando CharacterBody2D e GDScript. Cobrimos:

  • A estrutura de nós para um inimigo.
  • Como usar _physics_process e move_and_slide para movimento.
  • Lógica para mudar de direção e animar o sprite.
  • Melhores práticas como @export e @onready.

Este é um passo fundamental! No futuro, poderemos adicionar:

  • Detecção de Jogador: Fazer o inimigo perseguir o jogador quando ele entra em uma área.
  • Ataque e Dano: Lógica para o inimigo atacar o jogador e causar dano.
  • Estados de Inimigo: Implementar uma máquina de estados (idle, walk, attack, hurt) para comportamentos mais complexos.

Continue praticando e experimentando! O mundo dos inimigos em jogos é vasto e cheio de possibilidades. 🎮✨

© 2025 Escola All Dev. Todos os direitos reservados.

Inimigos Simples: Movimento e Lógica Básica - Fundamentos do Godot: Desenvolvimento de games para iniciantes | escola.all.dev.br