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étodo | O que você controla | O que a física controla | Uso típico |
|---|---|---|---|
AddForce | A força aplicada | A velocidade resultante | Explosão, empurrão, foguete, carro |
linearVelocity | A velocidade | A posição e as colisões | Personagem, projétil, pulo |
MovePosition | A posição de destino | O empurrão em quem está no caminho | Plataforma, 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.
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.



