Voltar para o Blog
Quest Log

Vibração do Controle na Godot 4 (Rumble e Force Feedback)

Controle de videogame vibrando durante uma explosao em um jogo feito na Godot 4

Aprenda a fazer a vibração do controle na Godot 4 reagir a dano, tiro e explosão, controlar intensidade e duração e vibrar tambem no celular.

A vibração do controle na Godot 4 é um daqueles detalhes que separa um protótipo de um jogo que parece vivo. Quando o jogador toma dano e sente um baque na mão, ou quando um tiro sai e o controle dá um pulso curto, o cérebro conecta a ação à reação de um jeito que só o áudio e a imagem não conseguem. A boa notícia é que a Godot 4 já traz tudo que você precisa na classe Input, sem plugin nem addon. A má notícia (e é bom saber disso desde o começo) é que rumble depende de hardware e driver, então nem todo controle vai responder. Neste post você vai montar uma função utilitária de vibração, disparar ela em eventos de jogo, criar um padrão de pulso e ainda vibrar o celular.

O que a Godot 4 oferece para rumble

Toda a API de vibração vive na classe Input, que é global e você acessa de qualquer script. As funções principais são poucas e diretas:

  • Input.start_joy_vibration(device: int, weak_magnitude: float, strong_magnitude: float, duration: float = 0) começa a vibração. O device é o índice do controle (quase sempre 0 para o primeiro), weak_magnitude e strong_magnitude vão de 0.0 a 1.0 e duration é em segundos. Se duration for 0, a vibração continua até você mandar parar.
  • Input.stop_joy_vibration(device: int) para a vibração daquele controle na hora.
  • Input.get_joy_vibration_strength(device: int) -> Vector2 devolve a intensidade atual (x = fraco, y = forte).
  • Input.get_joy_vibration_duration(device: int) -> float devolve quanto tempo de vibração ainda resta.
  • Input.get_connected_joypads() -> Array lista os controles conectados, útil para checar se existe alguém para vibrar antes de tentar.

O detalhe que muita gente ignora é a diferença entre os dois motores. O weak_magnitude controla o motor pequeno, de alta frequência, que produz uma vibração fina e nervosa, ótima para tiros rápidos e feedback de menu. O strong_magnitude controla o motor grande, de baixa frequência, que dá um baque pesado, perfeito para explosões e dano. Brincar com a mistura dos dois é o que faz cada evento ter uma textura própria.

Uma função utilitária para vibrar

Espalhar chamadas de start_joy_vibration pelo código inteiro é receita para dor de cabeça. Melhor centralizar tudo em uma função, de preferência num autoload (singleton). Assim você tem um único lugar para checar se há controle conectado, respeitar a configuração do jogador e ajustar o comportamento no futuro.

Crie um script feedback.gd, registre ele como autoload com o nome Feedback e escreva:

extends Node

## Ligado por padrao; o jogador pode desligar nas opcoes.
var vibracao_ligada: bool = true

func vibrar(fraco: float, forte: float, dur: float) -> void:
    if not vibracao_ligada:
        return
    # Sem controle conectado, nao ha o que vibrar.
    if Input.get_connected_joypads().is_empty():
        return
    Input.start_joy_vibration(0, fraco, forte, dur)

func parar_vibracao() -> void:
    Input.stop_joy_vibration(0)

Repare em três decisões. Primeiro, se a vibração estiver desligada nas opções, a função retorna sem fazer nada. Segundo, se não houver nenhum controle conectado (get_connected_joypads() vazio), também retornamos, evitando chamadas inúteis. Terceiro, os parâmetros ficam explícitos e tipados, então em qualquer lugar do jogo você lê Feedback.vibrar(0.2, 0.8, 0.3) e entende na hora que é um baque forte e curto.

Se o seu jogo tem controle de teclado e joystick, vale entender como a Godot trata cada dispositivo. Cobri isso em detalhe no guia de suporte a controle/joystick na Godot, que ajuda a mapear botões e eixos antes de pensar em rumble.

Vibrar ao tomar dano

Agora que existe Feedback.vibrar, disparar em eventos vira uma linha. No script do jogador, no ponto onde a vida diminui, chame a vibração com uma intensidade que combine com o baque de levar dano. Dano pede o motor forte, então mande strong_magnitude alto e weak_magnitude baixo:

extends CharacterBody2D

var vida: int = 100

func tomar_dano(quantidade: int) -> void:
    vida -= quantidade
    # Baque pesado e curto: motor forte alto, fraco baixo.
    Feedback.vibrar(0.1, 0.9, 0.25)
    if vida <= 0:
        morrer()

func morrer() -> void:
    Feedback.vibrar(0.0, 1.0, 0.6)
    # ... resto da logica de morte

Para um tiro, inverta a lógica. Um tiro de pistola é rápido e agudo, então use o motor fraco com duração bem curta:

func atirar() -> void:
    # ... instancia o projetil
    Feedback.vibrar(0.6, 0.1, 0.08)

E uma explosão perto do jogador merece os dois motores no talo por um instante um pouco mais longo:

func explosao_proxima() -> void:
    Feedback.vibrar(1.0, 1.0, 0.4)

Note como três eventos completamente diferentes usam a mesma função, só variando os números. Essa é a vantagem de centralizar: você afina o game feel em um lugar só, testando valores até cada evento ficar com a sensação certa.

Próximo nível
Quer aprender isso na prática?

No CursoGame.Dev você sai dos tutoriais soltos e constrói jogos publicáveis, com trilha progressiva, quests práticas e feedback real.

Conhecer a plataforma
+500 alunos4.9/5Garantia 7 dias

Padrão de pulso com timer

Uma única vibração contínua serve para a maioria dos casos, mas às vezes você quer um padrão, tipo três pulsos rápidos para sinalizar vida crítica ou um alarme. Como start_joy_vibration com duração já para sozinha, dá para encadear pulsos com await e um timer da árvore de cena:

func pulsar(vezes: int, fraco: float, forte: float, dur_pulso: float, intervalo: float) -> void:
    for i: int in range(vezes):
        vibrar(fraco, forte, dur_pulso)
        await get_tree().create_timer(dur_pulso + intervalo).timeout

Aqui a cada volta do laço a gente dispara um pulso e espera o tempo do pulso mais um intervalo de descanso antes do próximo. Chamar Feedback.pulsar(3, 0.0, 0.7, 0.12, 0.08) produz três batidas fortes e espaçadas. Como a função tem await, quem chamar também pode esperar por ela se quiser sincronizar com uma animação ou som.

Um cuidado: se o jogador desligar a vibração no meio de um pulso, o laço continua rodando mas vibrar simplesmente não faz nada, porque a checagem de vibracao_ligada está lá dentro. Silêncio garantido, sem quebrar o fluxo.

Vibrar o celular

Se você exporta para Android, o feedback tátil não precisa ficar de fora. A função é diferente porque o celular não tem dois motores separados como um controle:

func vibrar_celular(ms: int = 300) -> void:
    if not vibracao_ligada:
        return
    Input.vibrate_handheld(ms)

O Input.vibrate_handheld(duration_ms: int = 500) recebe a duração em milissegundos. Vale um aviso honesto de plataforma: no Android a duração é respeitada, mas no iOS a vibração dispara ignorando o valor que você passou, então não conte com controle fino de tempo no iPhone. Em jogos de celular a vibração costuma andar junto com controles na tela, e se esse é o seu caso o guia de controles touch no celular mostra como montar um joystick virtual que combina bem com esse feedback.

Consultar o estado da vibração

Às vezes você quer saber se o controle já está vibrando antes de disparar outra coisa, para não sobrepor efeitos de um jeito estranho. As funções de consulta ajudam:

func esta_vibrando() -> bool:
    var forca: Vector2 = Input.get_joy_vibration_strength(0)
    return forca.length() > 0.0

func tempo_restante() -> float:
    return Input.get_joy_vibration_duration(0)

Com isso você pode, por exemplo, deixar uma explosão sobrescrever um tiro em andamento, mas evitar que dois tiros seguidos criem um chiado contínuo indesejado. É micro-ajuste, mas é exatamente esse tipo de polimento que compõe o game feel e juice de um jogo que agrada na mão.

A opção de desligar (e por que ela importa)

Vibração não agrada todo mundo. Tem quem ache cansativo, tem quem jogue em contexto onde barulho de motor incomoda e tem gente com sensibilidade tátil. Por isso a opção de desligar não é enfeite, é acessibilidade básica. Como já deixamos a variável vibracao_ligada no autoload, o menu de opções só precisa alterá-la:

func _on_checkbox_vibracao_toggled(ativado: bool) -> void:
    Feedback.vibracao_ligada = ativado
    if not ativado:
        Feedback.parar_vibracao()

Quando o jogador desmarca a caixa, além de bloquear novas vibrações, chamamos parar_vibracao para cortar qualquer efeito que já esteja rolando. E não esqueça de salvar essa preferência no arquivo de configuração do jogo, junto com volume e resolução, para que a escolha persista entre sessões.

Limites que você precisa aceitar

Antes de fechar, vale repetir o aviso do começo com todas as letras, porque ele evita horas de depuração inútil. Rumble depende do driver e da camada SDL que a Godot usa por baixo. Nem todo controle tem motores de vibração, controles genéricos baratos às vezes não expõem rumble corretamente, o suporte no export para web (navegador) é limitado e inconsistente entre navegadores, e mesmo com o código impecável a Godot não garante o efeito em todo hardware. Então, se não vibrar, o primeiro passo é testar em um controle que você sabe que funciona (um Xbox ou DualShock no cabo é uma aposta segura) antes de suspeitar do seu código.

Conclusão e próximo passo

Você já tem o essencial: uma função vibrar(fraco, forte, dur) centralizada, disparos em dano, tiro e explosão, um padrão de pulso com await e timer, vibração no celular e uma opção de desligar que respeita o jogador. O próximo passo é sentar com um controle na mão e afinar os números de cada evento, porque game feel se descobre testando, não no papel. Ajuste até cada baque parecer inevitável. Se quiser continuar aprofundando essa camada de resposta sensorial do jogo, siga para o material sobre game feel e juice e transforme os efeitos que você montou aqui em algo realmente memorável no CursoGame.Dev.

Perguntas frequentes

Como fazer o controle vibrar na Godot 4?

Use Input.start_joy_vibration(device, weak_magnitude, strong_magnitude, duration). O device costuma ser 0 para o primeiro controle, weak e strong vao de 0.0 a 1.0 e duration e em segundos. Passe 0 na duracao para vibrar ate chamar stop_joy_vibration.

Qual a diferenca entre weak_magnitude e strong_magnitude?

weak_magnitude controla o motor pequeno de alta frequencia (uma vibracao mais fina e nervosa) e strong_magnitude controla o motor grande de baixa frequencia (um baque pesado). Misturar os dois da texturas diferentes para cada evento do jogo.

Da para vibrar o celular na Godot 4?

Sim, com Input.vibrate_handheld(duration_ms). No Android a duracao em milissegundos e respeitada. No iOS a chamada dispara a vibracao mas ignora a duracao que voce passou.

Por que meu controle nao vibra mesmo com o codigo certo?

Rumble depende de driver, do SDL e do hardware do controle. Nem todo joystick tem motores, o suporte no navegador (export web) e limitado e a Godot nao garante o efeito em todo hardware. Teste em um controle que voce sabe que vibra.

Como deixar o jogador desligar a vibracao?

Guarde uma variavel de configuracao como vibracao_ligada e cheque ela dentro da sua funcao utilitaria de vibrar. Se estiver desligada, apenas retorne sem chamar start_joy_vibration. Salve essa opcao no arquivo de config do jogo.