Voltar para o Blog
Quest Log

Rigidbody na Unity: AddForce, Velocity e MovePosition

Três cubos num piso quadriculado, cada um com uma seta de cor diferente indicando força, velocidade e movimento direto

Unity Rigidbody na prática: AddForce com ForceMode, linearVelocity e MovePosition lado a lado, qual usar no pulo, no personagem e na plataforma no Unity 6.

Ferramenta:UnityC#

Rigidbody na Unity: AddForce, Velocity e MovePosition

Unity Rigidbody é o componente que entrega um objeto para o motor de física: com ele, o objeto cai, colide, é empurrado e empurra. Para mover esse objeto por código você tem três caminhos: AddForce (aplica força e deixa a física resolver), linearVelocity (você manda a velocidade exata) e MovePosition (você manda a posição, ideal para corpos Kinematic). Cada um serve para um tipo de movimento, e misturar os três sem critério é o que faz o personagem deslizar, a plataforma tremer e o pulo variar de altura.

No fim deste post você vai ter os três lado a lado, com código C# que compila no Unity 6.3 LTS, um critério para escolher entre eles no pulo, no personagem e na plataforma, e os nomes de API que mudaram no Unity 6 e quebram código copiado de fórum.

Unity Rigidbody: o que ele faz

Um GameObject com Collider e sem Rigidbody é uma parede: outros objetos batem nele, mas ele não se mexe sozinho. Quando você adiciona um Rigidbody (Add Component > Physics > Rigidbody), o objeto passa a ser simulado no passo de física: gravidade, massa, colisões e forças agem sobre ele a cada FixedUpdate.

Isso muda uma regra que confunde muita gente no começo: quem move um Rigidbody é a física. Se você escreve transform.position += ... num objeto com Rigidbody, está teleportando o objeto por fora do simulador. A física descobre o teleporte no passo seguinte e tenta corrigir, e o resultado é objeto atravessando parede ou tremendo encostado nela.

Os três métodos deste post conversam com o simulador em vez de passar por cima dele. A diferença entre eles é quanto controle você entrega para a física:

MétodoO que você controlaO que a física controlaUso típico
AddForceA força aplicadaA velocidade resultanteExplosão, empurrão, foguete, carro
linearVelocityA velocidadeA posição e as colisõesPersonagem, projétil, pulo
MovePositionA posição de destinoO empurrão em quem está no caminhoPlataforma, elevador, porta

Antes do código, um aviso sobre nomes. No Unity 6 a velocidade linear do Rigidbody se chama linearVelocity, o arrasto se chama linearDamping e o arrasto de rotação se chama angularDamping. Tutorial que usa rb.velocity e rb.drag mostra os nomes antigos: o editor marca como obsoleto. A documentação do Rigidbody no Unity 6.3 lista só os nomes novos.

AddForce e os ForceModes

AddForce soma uma força ao que o corpo já está fazendo. Se o objeto vinha a 10 m/s para a direita e você aplica força para a esquerda, ele desacelera, não para na hora. Essa soma é o que dá a sensação de peso e inércia.

O segundo parâmetro, ForceMode, define como a força entra. A documentação lista quatro modos:

  • Force: força contínua, considera a massa. Feita para ser chamada a cada FixedUpdate (motor de carro, propulsor).
  • Acceleration: aceleração contínua, ignora a massa. Mesmo efeito em qualquer corpo.
  • Impulse: força instantânea, considera a massa. Um golpe, uma explosão.
  • VelocityChange: mudança instantânea de velocidade, ignora a massa.

A pergunta prática é: a massa deve importar? Numa explosão, sim: caixa pesada voa menos que caixa leve, então Impulse. No pulo do jogador, quase nunca: você quer a mesma altura independente da massa que alguém colocou no Inspector, então VelocityChange.

Arquivo Propulsor.cs, um objeto que acelera para frente enquanto a tecla está apertada e leva um empurrão lateral no espaço:

using UnityEngine;
using UnityEngine.InputSystem;

[RequireComponent(typeof(Rigidbody))]
public class Propulsor : MonoBehaviour
{
    [SerializeField] private float forcaMotor = 20f;
    [SerializeField] private float impulsoLateral = 5f;

    private Rigidbody rb;
    private bool acelerando;
    private bool pedirEmpurrao;

    private void Awake()
    {
        rb = GetComponent<Rigidbody>();
    }

    private void Update()
    {
        // Input lido no Update, aplicado no FixedUpdate.
        acelerando = Keyboard.current != null && Keyboard.current.wKey.isPressed;

        if (Keyboard.current != null && Keyboard.current.spaceKey.wasPressedThisFrame)
        {
            pedirEmpurrao = true;
        }
    }

    private void FixedUpdate()
    {
        if (acelerando)
        {
            rb.AddForce(transform.forward * forcaMotor, ForceMode.Force);
        }

        if (pedirEmpurrao)
        {
            rb.AddForce(transform.right * impulsoLateral, ForceMode.Impulse);
            pedirEmpurrao = false;
        }
    }
}

Repare na separação: o input é lido no Update (que roda a cada frame e não perde o wasPressedThisFrame) e a força é aplicada no FixedUpdate (que roda no passo de física). Força contínua no Update varia com o FPS; impulso lido no FixedUpdate às vezes perde o aperto da tecla. O post sobre delta time e movimento por frame explica por que esses dois relógios andam em ritmos diferentes.

linearVelocity: controle direto

Atribuir rb.linearVelocity substitui a velocidade atual pela que você mandou. Não há inércia: o corpo vai exatamente na velocidade pedida, e a física cuida só das colisões e da gravidade (se você preservar o eixo Y).

É o caminho mais usado para personagem controlado pelo jogador, porque o jogador espera que soltar o direcional pare o boneco, não que ele deslize como em gelo.

Arquivo MovimentoRigidbody.cs, personagem 3D com movimento e pulo usando as ações padrão do Input System (o template de projeto do Unity 6 já vem com as ações Move e Jump):

using UnityEngine;
using UnityEngine.InputSystem;

[RequireComponent(typeof(Rigidbody))]
public class MovimentoRigidbody : MonoBehaviour
{
    [SerializeField] private float velocidade = 6f;
    [SerializeField] private float velocidadePulo = 7f;
    [SerializeField] private LayerMask camadaChao;

    private Rigidbody rb;
    private InputAction acaoMover;
    private InputAction acaoPular;
    private Vector2 entrada;
    private bool pedirPulo;

    private void Awake()
    {
        rb = GetComponent<Rigidbody>();
        rb.freezeRotation = true; // personagem não tomba
        acaoMover = InputSystem.actions.FindAction("Move");
        acaoPular = InputSystem.actions.FindAction("Jump");
    }

    private void Update()
    {
        entrada = acaoMover.ReadValue<Vector2>();
        if (acaoPular.WasPressedThisFrame())
        {
            pedirPulo = true;
        }
    }

    private void FixedUpdate()
    {
        Vector3 direcao = new Vector3(entrada.x, 0f, entrada.y) * velocidade;

        // Mantém o Y da física para a gravidade continuar agindo.
        Vector3 v = rb.linearVelocity;
        v.x = direcao.x;
        v.z = direcao.z;

        if (pedirPulo && EstaNoChao())
        {
            v.y = velocidadePulo;
        }
        pedirPulo = false;

        rb.linearVelocity = v;
    }

    private bool EstaNoChao()
    {
        return Physics.Raycast(transform.position, Vector3.down, 1.1f, camadaChao);
    }
}

O detalhe que mais quebra esse script quando é copiado: zerar o Y. Se você escrever rb.linearVelocity = direcao; com direcao.y = 0, a cada passo de física você apaga a queda e o personagem flutua descendo devagar. Copie a velocidade atual, troque só X e Z, e mexa no Y apenas no pulo.

O 1.1f do raycast assume uma cápsula de 2 metros com pivô no centro. Ajuste para o seu modelo e coloque o chão numa layer própria no camadaChao.

MovePosition e Kinematic

Plataforma móvel não deveria cair, ser empurrada pelo jogador nem perder o trajeto ao levar uma pancada. Para isso existe o Rigidbody com Is Kinematic marcado: a física não aplica gravidade nem forças nele, mas ele continua participando das colisões e empurra corpos dinâmicos.

Para mover um corpo Kinematic, use MovePosition dentro do FixedUpdate. Ele calcula o deslocamento como movimento de verdade (não teleporte), e com Interpolate ligado no Inspector o objeto aparece suave entre um passo de física e outro.

Arquivo PlataformaMovel.cs, plataforma que vai e volta entre dois pontos:

using UnityEngine;

[RequireComponent(typeof(Rigidbody))]
public class PlataformaMovel : MonoBehaviour
{
    [SerializeField] private Vector3 deslocamento = new Vector3(4f, 0f, 0f);
    [SerializeField] private float duracaoIda = 2f;

    private Rigidbody rb;
    private Vector3 pontoA;
    private Vector3 pontoB;

    private void Awake()
    {
        rb = GetComponent<Rigidbody>();
        rb.isKinematic = true;
        rb.interpolation = RigidbodyInterpolation.Interpolate;
        pontoA = rb.position;
        pontoB = pontoA + deslocamento;
    }

    private void FixedUpdate()
    {
        float t = Mathf.PingPong(Time.fixedTime / duracaoIda, 1f);
        Vector3 destino = Vector3.Lerp(pontoA, pontoB, t);
        rb.MovePosition(destino);
    }
}

Se você quer só reposicionar o objeto de uma vez (respawn, checkpoint), use rb.position = novaPosicao;. Ele teleporta sem simular o caminho, que é o que você quer num respawn e o que você não quer numa plataforma.

Os três scripts acima funcionam isolados. O trabalho de verdade aparece quando o personagem com linearVelocity precisa subir na plataforma com MovePosition, levar um Impulse de uma explosão e continuar respondendo ao controle, tudo com câmera e animação acompanhando. É nessa costura que um projeto solo costuma travar, e é o tipo de coisa que o curso de Unity monta passo a passo dentro de um jogo inteiro.

Curso de Unity
Quer fazer seu primeiro jogo na Unity?

No curso de Unity 6 da CursoGame.Dev você vai do zero ao primeiro jogo, com um desafio prático em cada level e suporte individual no WhatsApp quando travar.

Conhecer o curso de Unity
Suporte no WhatsAppAcesso vitalícioGarantia de 7 dias

Qual usar: pulo, personagem, plataforma

Um critério que resolve a maioria dos casos:

Pulo. Atribua linearVelocity.y diretamente, ou use AddForce(Vector3.up * valor, ForceMode.VelocityChange). Os dois dão a mesma altura sempre. Só use Impulse se você quer que personagens com massas diferentes pulem alturas diferentes de propósito. Um detalhe: com AddForce, se o personagem estiver caindo quando o pulo dispara (coyote time, pulo duplo), a força é somada a uma velocidade negativa e o pulo sai baixo. Zerar o Y antes resolve: v.y = 0f e depois o impulso.

Personagem controlado pelo jogador. linearVelocity nos eixos horizontais, preservando o Y. Se você quer aceleração e frenagem suaves, use Vector3.MoveTowards na velocidade atual em vez de trocar por AddForce: o controle continua seu e a curva fica do jeito que você desenhou. Se a dúvida é se o personagem deveria nem usar Rigidbody, o comparativo Character Controller vs Rigidbody passa pelos critérios.

Plataforma, porta, elevador. Rigidbody Kinematic com MovePosition (e MoveRotation para girar). Nunca transform.position.

Projétil. linearVelocity uma vez, no momento do disparo, e deixe a física carregar. Para bala muito rápida, troque por raycast.

Objeto de cenário que reage (caixa, barril, destroço). Não mova por código. Deixe a física e aplique Impulse ou AddExplosionForce quando algo acontecer com ele.

Mass, Damping e Interpolate

Três campos do Inspector mudam como os métodos acima se comportam:

Mass. Afeta Force e Impulse, não afeta Acceleration, VelocityChange nem atribuição direta de linearVelocity. Também decide quem empurra quem numa colisão entre corpos dinâmicos. Mantenha as massas numa faixa próxima (algo como 0,1 a 10 vezes uma da outra): diferenças enormes deixam o solver instável.

Linear Damping e Angular Damping. Resistência que freia o corpo a cada passo. Damping alto num personagem com AddForce dá um movimento pesado, como andar na água. Num personagem com linearVelocity atribuída todo passo, o damping quase não aparece, porque você substitui a velocidade antes que ele acumule. Se você subiu o damping e "nada mudou", é isso.

Interpolate. O passo de física roda numa frequência fixa (50 Hz no padrão), e a tela pode rodar a 144 Hz. Sem interpolação, o objeto anda em degraus e a câmera que segue ele mostra tremedeira. Com Interpolate, a Unity suaviza a posição exibida entre os dois últimos passos. Ligue no jogador e em tudo que a câmera acompanha de perto; deixe desligado em objetos de cenário para não gastar à toa.

Erros comuns com Rigidbody

Usar velocity e drag. No Unity 6 o compilador avisa que estão obsoletos. Troque por linearVelocity e linearDamping.

Aplicar força no Update. ForceMode.Force chamado no Update depende do FPS: em 30 FPS o carro anda devagar, em 200 FPS voa. Leia input no Update, aplique no FixedUpdate.

Ler wasPressedThisFrame no FixedUpdate. Se o jogo roda mais frames que passos de física, o aperto acontece num frame sem FixedUpdate e é perdido. Guarde num booleano no Update, como nos exemplos.

Mover pelo transform um objeto com Rigidbody. O objeto atravessa colisores finos e treme em paredes. Use os métodos do Rigidbody.

Personagem tombando. Marque Freeze Rotation X e Z em Constraints (ou rb.freezeRotation = true como no script). Sem isso, qualquer quina derruba a cápsula.

Personagem grudando na parede durante o pulo. O atrito do collider segura o corpo contra a parede enquanto o jogador empurra para ela. A correção é um Physics Material com atrito zero no personagem.

Plataforma Kinematic que não carrega o jogador. MovePosition empurra quem está na frente, mas quem está em cima depende do atrito para ir junto, e o script do personagem sobrescreve X e Z a cada passo, apagando esse arrasto. A solução comum é somar a velocidade da plataforma à do jogador enquanto ele está em contato com ela, ou tornar o jogador filho da plataforma enquanto pisa nela.

Próximo passo

Monte uma cena de teste com os três scripts: um cubo com Propulsor, uma cápsula com MovimentoRigidbody e uma plataforma com PlataformaMovel. Suba a cápsula na plataforma, observe o problema de carregar o jogador e resolva somando a velocidade. Depois troque o ForceMode do pulo e mude a massa da cápsula para ver na prática quais modos ignoram a massa.

Se você também usa Godot ou está decidindo entre as duas engines, o guia de física de jogos no Godot mostra os mesmos conceitos (corpo rígido, cinemático e estático) com os nomes de lá, e ajuda a entender que o modelo mental é o mesmo nas duas.

Perguntas frequentes

Qual a diferença entre AddForce e velocity na Unity?

AddForce soma uma força ou impulso ao que o corpo já está fazendo e deixa a física calcular o resultado. Atribuir linearVelocity substitui a velocidade atual pelo valor que você mandou. Use AddForce quando quer reação física (explosão, empurrão) e linearVelocity quando quer controle exato (andar, parar na hora).

Rigidbody.velocity não existe mais no Unity 6?

No Unity 6 a propriedade se chama Rigidbody.linearVelocity, e o arrasto se chama linearDamping. O nome velocity dos tutoriais antigos aparece como obsoleto no editor. Troque os dois nomes e o comportamento é o mesmo.

Quando usar MovePosition na Unity?

MovePosition serve para mover um Rigidbody Kinematic, como plataforma móvel, porta ou elevador, respeitando a interpolação e empurrando corpos dinâmicos no caminho. Chame dentro de FixedUpdate, com a posição de destino do passo de física atual.

Qual ForceMode usar para pulo na Unity?

ForceMode.Impulse aplica a força de uma vez e considera a massa, então personagens mais pesados pulam menos com o mesmo valor. ForceMode.VelocityChange ignora a massa e dá a mesma altura para qualquer corpo. Para pulo de personagem, VelocityChange ou atribuir linearVelocity.y direto dão o resultado mais previsível.