Isenção de responsabilidade: provavelmente existem outras e melhores maneiras de fazer isso. De qualquer maneira, vou compartilhar e descrever a maneira como lidei com esse problema há algum tempo, o que acabou funcionando bem para mim.
Eu implementei um jogo de carros 2D de cima para baixo há alguns anos para um projeto universitário e, se bem me lembro, usei este artigo como ponto de partida, embora tenha acabado simplificando muito e descartado tudo isso " roda "modelando coisas a favor de um único corpo para o carro. O que eu usei, no entanto, foi algo semelhante ao KillOrthogonalVelocity
método que você pode encontrar lá, para cuidar da aplicação do atrito lateral.
Então, aqui está um pequeno vídeo de como ficou. Há uma certa quantidade de atrito lateral sendo aplicada, que também depende de eu estar usando o botão do freio de mão ou não, e o carro que usei para o vídeo também flutua significativamente mais do que os outros. Isso era controlável. Ele também tinha um caminhão com zero movimento lateral e controles muito rígidos.
Nunca fiquei completamente satisfeito com os resultados, mas foi o suficiente para minhas necessidades. Tenha em mente que eu não baseiei minha física em movimento real de veículo ou algo assim. Eu apenas agitei e tentei as coisas até que parecesse certo.
Fricção lateral
Portanto, para dar alguns detalhes sobre a implementação, basicamente, quando adaptei esse método ao meu projeto, adicionei uma variável que me permitia controlar exatamente quanto da velocidade lateral eu mataria, como um valor entre 0 e 1. Isso me permitiu ajustar o manuseio do carro e o quanto ele poderia flutuar. Aqui está o método traduzido para o XNA e simplificado:
public static void KillOrthogonalVelocity(Car car, float drift = 0f)
{
Vector2 forwardVelocity = car.Forward * Vector2.Dot(car.Velocity, car.Forward);
Vector2 rightVelocity = car.Right * Vector2.Dot(car.Velocity, car.Right);
car.Velocity = forwardVelocity + rightVelocity * drift;
}
Como você pode ver, eu estou usando vetores e álgebra linear, não trigonometria, então você terá que adaptá-lo às suas necessidades. Ambos car.Forward
e car.Right
são vectores normalizados que apontam em que direcção particular.
Acelerador, freios, direção
Fora isso, a única outra parte relevante era como apliquei as forças no carro para fazê-lo se mover e dirigir:
- Acelerar e frear era simples. Apenas uma questão de aplicar uma força na direção que o carro estava no momento, ou seu inverso.
A direção, por outro lado, teve alguns truques. A direção foi feita aplicando um torque ao carro (usei o Box2D, portanto, essa era uma simples chamada de método), mas a potência desse torque dependia de alguns fatores, em particular:
- Ao quebrar, aumentei o torque em 25% para possibilitar curvas mais nítidas.
if(braking || handbraking) torque *= 1.25
- Ao dar marcha à ré, também invertai o torque para obter os controles corretos.
if(reverse) torque *= -1
- Finalmente, se o carro estava passando por um certo limite de velocidade, eu o fazia dirigir menos que o normal.
if(speed < 2.0f) torque *= (speed / 4.0f)
Em seguida, basta chamar o KillOrthogonalVelocity()
método para ajustar a velocidade final e fazê-lo se comportar menos como uma nave espacial e mais como um carro.