Rover v0 em raycast, do zero
Vou refazer o protótipo por raycast, tratando a caixa teal do diagrama — o contato com o solo — como requisito de projeto, não consequência. Ou seja: construo o contrato primeiro e o carro em volta dele. Três entregáveis, na ordem.
Os três entregáveis
RigidBody3D com quatro RayCast3D nos cantos — sem VehicleBody3D, sem VehicleWheel3D. Cada roda calcula três forças e aplica com apply_force no ponto de contato. A meta não é um carro bonito andando: é cada força nomeada e isolada.ground_contact.gd. O resto do veículo só enxerga uma função — então trocar pela ExoPhysics depois não toca em mais nada.A semana, dia a dia
Ritmo calmo: fazer o carro parar em pé, depois andar, depois virar — uma força por vez.
Repo, regra e esqueleto
Preparar o repo. Criar o ground_contact.gd e colar o contrato em C++ como comentário já no commit 1 (seção abaixo). Montar o RigidBody3D + 4 RayCast3D nos cantos. A regra "raycast só aqui" nasce hoje e vale a semana inteira.
Mola–amortecedor (ao longo da normal)
A suspensão. Com ela o carro senta e para em pé sobre os quatro raios. É a força mais densa — vale caprichar aqui.
→ Octodemy · Parte 1 (Suspensions)Longitudinal (tração / frenagem)
Agora o carro anda pra frente e pra trás. Força aplicada no ponto de contato, na direção de rolagem da roda.
Atrito lateral (o grip)
O que impede a derrapagem. Com ela o carro vira sem escorregar de lado. Fecha as três forças.
Juntar e isolar
As três forças rodando juntas. Conferir o principal: cada uma nomeada e isolada, e nenhum raycast vazou de ground_contact.gd — o veículo só chama query_wheel_contact().
Doc: raycast ↔ Bloco 5
Escrever a página mapeando o modelo de força de penalidade na tabela de corpos/juntas (prismática/revoluta). Tabela pronta na seção abaixo.
Limpar e fechar
README, histórico de commits arrumado, contrato revisado no repo, doc relida. Dia de folga técnica / buffer.
Três entregáveis na mão
Repo rodando, contrato plantado e o mapeamento escrito — pronto pra próxima conversa.
A regra que segura tudo
Todo o contato com o solo mora num único arquivo, ground_contact.gd. O resto do veículo só conhece uma função. Quando a ExoPhysics existir, troco a implementação por trás dessa função e não toco em mais nada. O contrato final é em C++ (a ExoPhysics), mas o ground_contact.gd em GDScript já devolve exatamente esse formato desde a v0.
struct WheelState {
Vec3 position, linear_velocity;
Quat orientation;
float angular_velocity; // rotação da roda
float radius, width;
float normal_load_prev; // carga do passo anterior
};
struct ContactResult {
bool in_contact;
Vec3 point, normal;
float sinkage; // afundamento — só com solo deformável
Vec3 force, torque;
};
ContactResult query_wheel_contact(const WheelState& w, double dt);Detalhe no sinkage: na v0 ele vem sempre zero. É a prova de que o contrato já nasceu pensando no solo deformável — e é exatamente a peça que a Luana precisa ver pra alinhar o lado dela.
Amarrando no Bloco 5
O mesmo canto do rover, resolvido de dois jeitos diferentes.
O ponto da doc: o raycast não tem junta nenhuma — ele chega no mesmo resultado por penalidade em vez de restrição. Escrever isso lado a lado é o que transforma o Bloco 5 numa pergunta concreta pro professor.