Fundamentos do Godot: Desenvolvimento de games para iniciantes
Manipulando Input: Teclado e Mouse
Aprenda sobre manipulando input: teclado e mouse
Manipulando Input: Teclado e Mouse
Olá, futuro desenvolvedor de games! 👋 Nesta aula prática, vamos mergulhar em um dos aspectos mais fundamentais de qualquer jogo interativo: a manipulação de inputs do jogador. Seja para mover um personagem, atirar ou interagir com o ambiente, entender como Godot processa os comandos do teclado e do mouse é essencial.
Vamos aprender a capturar e responder a eventos de teclado e mouse usando GDScript, focando nas melhores práticas para criar controles responsivos e flexíveis. Preparado para dar vida aos seus jogos? ✨
1. Entendendo o Fluxo de Input no Godot 🎮
Godot oferece duas abordagens principais para lidar com input:
a) _input(event): O Tratador de Eventos
Esta função é chamada sempre que um evento de input ocorre. É ideal para inputs que acontecem em um momento específico, como um clique de mouse, o pressionar de uma tecla, ou o movimento do mouse. O Godot envia um objeto InputEvent que você pode inspecionar para saber o tipo de input e seus detalhes.
- Vantagem: Reage instantaneamente a eventos, processa apenas quando algo acontece.
- Desvantagem: Não é ideal para inputs contínuos (como manter uma tecla pressionada para mover um personagem), pois ele só detecta o "pressionar" inicial e o "soltar". Para isso, usaremos o
_processem conjunto com oInputsingleton.
b) _process(delta): O Loop Contínuo
Como vimos na aula anterior, _process é chamado a cada frame. Podemos usá-lo em conjunto com o singleton Input (que é um objeto global disponível em qualquer lugar) para verificar o estado atual de uma tecla ou botão do mouse.
- Vantagem: Ideal para inputs contínuos (ex: movimento do personagem enquanto a tecla está pressionada).
- Desvantagem: É chamado a cada frame, mesmo que não haja input, o que pode ser menos eficiente para inputs pontuais.
Nesta aula, focaremos principalmente em _input para eventos pontuais e no Input singleton para estados contínuos, combinando-os com o Mapa de Ações (Input Map) para uma organização superior.
2. Configurando o Mapa de Ações (Input Map) 🗺️
Antes de mergulharmos no código, a melhor prática em Godot é definir ações de input em vez de verificar teclas ou botões do mouse diretamente. Isso torna seu jogo mais flexível, permitindo que os jogadores reconfigurem os controles e facilitando a portabilidade para diferentes plataformas (gamepads, touchscreens, etc.).
Passos para configurar o Input Map:
- Vá em
Projeto->Configurações do Projeto... - Selecione a aba
Mapa de Ações. - No campo
Ação, digite um nome para sua nova ação (ex:mover_para_frente,atirar,pular). - Clique no botão
Adicionar. - Com a nova ação selecionada, clique no ícone
+ao lado direito para adicionar um evento de input a ela. - Pressione a tecla ou clique o botão do mouse que você deseja associar a essa ação.
Vamos criar algumas ações básicas para nossos exercícios:
move_left: TeclaAouSeta Esquerdamove_right: TeclaDouSeta Direitajump: TeclaEspaçoshoot: Botão esquerdo do mouse (Mouse Button Index 1)

Exemplo de configuração do Mapa de Ações no Godot.
3. Manipulando Input do Teclado ⌨️
Vamos criar um script simples para detectar o pressionar e soltar de teclas através do Input Map.
- Crie uma nova cena 2D (Node2D).
- Adicione um
Labelcomo filho para exibir as mensagens. - Salve a cena como
InputTester.tscn. - Anexe um novo script chamado
InputTester.gdao nóNode2D.
# InputTester.gd
extends Node2D
@onready var message_label = $"Label"
func _ready():
message_label.text = "Pressione A/D para mover, Espaço para pular, Clique Esquerdo para atirar."
func _input(event):
# --- Verificando Ações de Teclado ---
if event.is_action_pressed("move_left"):
message_label.text = "Ação: Mover para Esquerda (Pressionado)"
print("Ação: move_left Pressionada!")
elif event.is_action_released("move_left"):
message_label.text = "Ação: Mover para Esquerda (Solto)"
print("Ação: move_left Solta!")
if event.is_action_pressed("move_right"):
message_label.text = "Ação: Mover para Direita (Pressionado)"
print("Ação: move_right Pressionada!")
elif event.is_action_released("move_right"):
message_label.text = "Ação: Mover para Direita (Solto)"
print("Ação: move_right Solta!")
if event.is_action_pressed("jump"):
message_label.text = "Ação: Pular (Pressionado)"
print("Ação: jump Pressionada!")
elif event.is_action_released("jump"):
message_label.text = "Ação: Pular (Solto)"
print("Ação: jump Solta!")
# --- Verificando Ações de Mouse (apenas o clique esquerdo por enquanto) ---
if event.is_action_pressed("shoot"):
message_label.text = "Ação: Atirar (Pressionado)"
print("Ação: shoot Pressionada!")
elif event.is_action_released("shoot"):
message_label.text = "Ação: Atirar (Solto)"
print("Ação: shoot Solta!")
Explicação do Código:
@onready var message_label = $"Label": Obtém uma referência ao nóLabelpara atualizar seu texto._ready(): Define o texto inicial doLabel._input(event): Esta função é o coração da detecção de eventos.event.is_action_pressed("nome_da_acao"): Retornatrueapenas no frame em que a ação foi pressionada. Útil para ações pontuais como pular ou atirar.event.is_action_released("nome_da_acao"): Retornatrueapenas no frame em que a ação foi solta.
Input Contínuo com _process e Input Singleton
Para inputs que precisam ser verificados continuamente (como mover um personagem enquanto a tecla está pressionada), usamos o singleton Input dentro de _process.
# Adicione este bloco ao seu InputTester.gd, ou crie um novo script para testar movimento.
extends Node2D
@onready var message_label = $"Label"
var player_speed = 100
func _process(delta):
var direction = Vector2.ZERO
# Verifica se a ação está sendo mantida pressionada
if Input.is_action_pressed("move_left"):
direction.x = -1
message_label.text = "Movendo para Esquerda..."
elif Input.is_action_pressed("move_right"):
direction.x = 1
message_label.text = "Movendo para Direita..."
else:
if message_label.text.begins_with("Movendo"): # Limpa a mensagem se não estiver movendo
message_label.text = "Pressione A/D para mover, Espaço para pular, Clique Esquerdo para atirar."
# Exemplo de movimento (assumindo que este script está em um Player com Position2D)
# self.position += direction * player_speed * delta
# Exemplo de ação "just_pressed" e "just_released" com o singleton Input
if Input.is_action_just_pressed("jump"):
print("Godot: Pulo iniciado!")
# Adicione lógica de pulo aqui
if Input.is_action_just_released("jump"):
print("Godot: Pulo finalizado!")
# Adicione lógica de finalização de pulo aqui
Explicação do Código Adicional:
Input.is_action_pressed("nome_da_acao"): Retornatrueenquanto a ação estiver sendo mantida pressionada. Ideal para movimento contínuo.Input.is_action_just_pressed("nome_da_acao"): Retornatrueapenas no frame em que a ação foi pressionada. Similar aoevent.is_action_pressed(), mas usado fora de_input.Input.is_action_just_released("nome_da_acao"): Retornatrueapenas no frame em que a ação foi solta. Similar aoevent.is_action_released(), mas usado fora de_input.
4. Manipulando Input do Mouse 🖱️
O mouse pode gerar diferentes tipos de eventos: cliques, movimento e scroll. Vamos focar nos cliques e movimento.
a) InputEventMouseButton (Cliques)
Quando um botão do mouse é clicado ou solto, um InputEventMouseButton é gerado.
# Adicione ou modifique o _input no seu InputTester.gd
extends Node2D
@onready var message_label = $"Label"
func _input(event):
# ... (código do teclado acima) ...
# --- Verificando Ações de Mouse (com Input Map) ---
if event.is_action_pressed("shoot"):
message_label.text = "Ação: Atirar (Pressionado)"
print("Ação: shoot Pressionada! Posição do mouse: ", event.position)
elif event.is_action_released("shoot"):
message_label.text = "Ação: Atirar (Solto)"
print("Ação: shoot Solta!")
# --- Verificando botões diretamente (menos recomendado, mas útil para debug) ---
if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_RIGHT and event.pressed:
message_label.text = "Botão Direito do Mouse Pressionado!"
print("Botão Direito do Mouse Pressionado em: ", event.position)
elif event.button_index == MOUSE_BUTTON_RIGHT and not event.pressed:
message_label.text = "Botão Direito do Mouse Solto!"
print("Botão Direito do Mouse Solto em: ", event.position)
Propriedades importantes de InputEventMouseButton:
button_index: Qual botão do mouse foi pressionado (ex:MOUSE_BUTTON_LEFT,MOUSE_BUTTON_RIGHT,MOUSE_BUTTON_MIDDLE).pressed:truese o botão foi pressionado,falsese foi solto.position: A posição global do mouse na tela no momento do evento.
b) InputEventMouseMotion (Movimento)
Quando o mouse se move, um InputEventMouseMotion é gerado.
# Adicione ou modifique o _input no seu InputTester.gd
extends Node2D
@onready var message_label = $"Label"
var last_mouse_pos = Vector2.ZERO
func _input(event):
# ... (código de teclado e mouse button acima) ...
if event is InputEventMouseMotion:
message_label.text = "Mouse movendo... Posição: " + str(event.position) + \
"\nRelativo: " + str(event.relative) + \
"\nVelocidade: " + str(event.velocity)
last_mouse_pos = event.position
# print("Mouse em: ", event.position, " Relativo: ", event.relative, " Velocidade: ", event.velocity)
Propriedades importantes de InputEventMouseMotion:
position: A posição global atual do mouse na tela.relative: A mudança na posição do mouse desde o último frame. Muito útil para câmeras ou rotação.velocity: A velocidade do mouse em pixels por segundo.
5. Exercícios Práticos 🚀
Agora é a sua vez de colocar a mão na massa! Use os conceitos que aprendemos para implementar os seguintes desafios.
Exercício 1: Movimento Básico de um Personagem 🚶♂️
Crie uma cena com um CharacterBody2D (ou Node2D com um Sprite2D e CollisionShape2D para simular um personagem). Faça-o se mover horizontalmente e pular usando as ações do Input Map que você configurou (move_left, move_right, jump).
Tarefas:
- Crie uma nova cena com um nó
CharacterBody2D(renomeie paraPlayer). - Adicione um
Sprite2D(pode ser umIcon.svgou um quadrado simples) e umCollisionShape2Dcomo filhos doPlayer. - Anexe um script ao
Player. - No
_physics_process(delta)(ideal para movimento de personagens), useInput.is_action_pressed()para detectarmove_leftemove_righte atualizar avelocity.xdoCharacterBody2D. - Use
Input.is_action_just_pressed()para detectarjumpe aplicar uma força vertical (velocity.y). - Aplique a gravidade e chame
move_and_slide()para o movimento.
# Exemplo de Player.gd para o Exercício 1
extends CharacterBody2D
const SPEED = 150.0
const JUMP_VELOCITY = -300.0 # Valor negativo para ir para cima
const GRAVITY = 800.0 # Ajuste conforme a necessidade do seu jogo
func _physics_process(delta):
# Aplica gravidade
if not is_on_floor():
velocity.y += GRAVITY * delta
# Lida com o pulo
if Input.is_action_just_pressed("jump") and is_on_floor():
velocity.y = JUMP_VELOCITY
# Lida com o movimento horizontal
var direction = Input.get_vector("move_left", "move_right", "ui_up", "ui_down") # ui_up/down são ignorados aqui para movimento 2D horizontal
if direction.x != 0:
velocity.x = direction.x * SPEED
else:
velocity.x = move_toward(velocity.x, 0, SPEED) # Desacelera o personagem
move_and_slide()
Exercício 2: Atirar na Direção do Mouse 🎯
Modifique a cena do InputTester ou crie uma nova. Ao clicar com o botão esquerdo do mouse (ação shoot), faça com que uma "bala" (pode ser outro Sprite2D simples) apareça na posição do jogador e se mova em direção à posição do mouse no momento do clique.
Tarefas:
- Crie uma cena de "bala" (
Bullet.tscn) com umSprite2De um script. A bala deve ter uma velocidade e se mover em sua_process(delta). - Na sua cena principal (ex:
InputTesterouPlayer), adicione umNode2DchamadoBulletSpawnPointcomo filho do seu personagem. - No script do seu personagem, carregue a cena da bala usando
preload()ouload(). - No
_input(event)ou_process(delta)(usandoInput.is_action_just_pressed("shoot")), instancie a cena da bala. - Defina a posição inicial da bala para a posição do
BulletSpawnPoint. - Calcule a direção do
BulletSpawnPointaté aevent.positiondo mouse (ouget_global_mouse_position()se usar_process). - Passe essa direção para a bala para que ela se mova corretamente.
- Adicione a bala como filho da cena principal (ex:
get_parent().add_child(bullet_instance)ouadd_child(bullet_instance)se a bala for independente do player).
# Exemplo de Player.gd (continuando do Exercício 1)
# Adicione estas variáveis no topo
var BulletScene = preload("res://scenes/bullet.tscn") # Crie esta cena primeiro!
@onready var bullet_spawn_point = $BulletSpawnPoint # Crie um Node2D chamado BulletSpawnPoint no Player
# Adicione esta função ao Player.gd
func _input(event):
if event.is_action_just_pressed("shoot"):
var bullet = BulletScene.instantiate()
get_parent().add_child(bullet) # Adiciona a bala à cena principal
bullet.global_position = bullet_spawn_point.global_position
var mouse_direction = (event.position - bullet_spawn_point.global_position).normalized()
bullet.set_direction(mouse_direction) # Você precisará criar esta função na sua Bullet.gd
# Exemplo de Bullet.gd
extends CharacterBody2D
var speed = 300.0
var direction = Vector2.RIGHT # Direção padrão
func _ready():
# Certifique-se de que o Sprite da bala esteja virado para a direita por padrão
# Se não, ajuste a rotação aqui se necessário
look_at(global_position + direction * 100) # Faz a bala "olhar" para a direção de movimento
func set_direction(dir: Vector2):
direction = dir
func _physics_process(delta):
velocity = direction * speed
move_and_slide()
# Opcional: Destruir a bala depois de um tempo ou fora da tela
# if global_position.x < -100 or global_position.x > 1200 or \
# global_position.y < -100 or global_position.y > 700:
# queue_free()
Exercício 3: Objeto Seguindo o Mouse 🐁
Crie uma cena simples com um Sprite2D. Faça com que este Sprite2D siga a posição do mouse em tempo real.
Tarefas:
- Crie uma nova cena com um
Node2D(renomeie paraMouseFollower). - Adicione um
Sprite2Dcomo filho. - Anexe um script ao
MouseFollower. - No
_process(delta), atualize aglobal_positiondoMouseFollowerparaget_global_mouse_position().
# MouseFollower.gd
extends Node2D
func _process(delta):
# Atualiza a posição do nó para seguir o mouse
global_position = get_global_mouse_position()
Resumo ✨
Nesta aula, exploramos a manipulação de input no Godot, cobrindo:
- A diferença entre
_input(event)para eventos pontuais e_process(delta)com o singletonInputpara estados contínuos. - A importância e configuração do Mapa de Ações (Input Map) para flexibilidade e organização.
- Como detectar o pressionar e soltar de teclas usando
is_action_pressed(),is_action_just_pressed(),is_action_released()eis_action_just_released(). - Como lidar com cliques (
InputEventMouseButton) e movimento do mouse (InputEventMouseMotion). - Praticamos criando um personagem que se move e pula, um sistema de tiro que mira no mouse e um objeto que segue o cursor.
Com essas ferramentas, você está pronto para criar interações complexas e intuitivas em seus jogos!
Próximos Passos ➡️
- Experimente: Tente adicionar mais ações ao seu Input Map (ex:
interagir,pausar). - Gamepads: Pesquise como o Godot lida com input de gamepads, o que é facilitado pelo uso de ações no Input Map.
- UI Input: Explore como os controles de UI (botões, sliders) gerenciam seus próprios eventos de input.
- Prioridade de Input: Entenda como o Godot decide qual nó recebe um evento de input primeiro (ordem da árvore de nós,
set_process_input()).
Continue praticando e criando! O input é a ponte entre o jogador e o seu mundo de jogo. Boas criações! 🚀