Criando atrito lateral em um piloto de cima para baixo em 2D

7

Eu tenho tentado criar algum tipo de corrida de cima para baixo, mas estou tendo problemas para fazer o carro girar corretamente. No momento, este é o código que tenho para atualizar a posição do carro:

var power;
    if (keyboard.upKeyDown) {
        power = 1;
    } else {
        power = 0;
    }

if (keyboard.leftKeyDown) {
    this.rotate -= 0.05;
} else if (this.keyboard.rightKeyDown) {
    this.rotate+= 0.05;
}

this.velocityX += Math.cos(this.rotate) * power;
this.velocityY += Math.sin(this.rotate) * power;

var cDrag = 0.98;
this.velocityX *= cDrag;
this.velocityY *= cDrag;

this.positionX += this.velocityX;
this.positionY += this.velocityY;

No momento em que o código é muito simples, você pressiona a tecla UP e a força é aplicada na direção em que está apontando, o que faz com que pareça um navio em asteróides.

Parece-me que a próxima coisa que preciso fazer é comparar a direção que o carro está apontando com a direção em que ele está realmente viajando e aplicar alguma força lateral para desacelerar na direção lateral, mas também transferir parte dessa força para a direção dianteira então continua na direção em que está apontando agora.

Estou um pouco confuso sobre como faço para fazer isso, para que qualquer conselho seja bem-vindo.

pogo
fonte

Respostas:

9

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 KillOrthogonalVelocitymé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.Forwarde car.Rightsã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:

    1. Ao quebrar, aumentei o torque em 25% para possibilitar curvas mais nítidas. if(braking || handbraking) torque *= 1.25
    2. Ao dar marcha à ré, também invertai o torque para obter os controles corretos. if(reverse) torque *= -1
    3. 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.

David Gouveia
fonte
Obrigado pela resposta, tentei implementar sua sugestão e parece estar funcionando muito bem. Definitivamente vou experimentar algumas das outras coisas que você mencionou sobre direção. Obrigado!
pogo 29/01