7
\$\begingroup\$

I've been playing around with trying to create some kind of top down racer but I'm having trouble getting the car to turn properly. At the moment this is the code I have to update the position of the car:

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;

At the moment the code is very simple, you hold down UP and force is applied in the direction you're pointing which makes it feel like the ship in asteroids.

It seems to me the next thing I need to do is compare the direction the car is pointing with the direction it's actually travelling and apply some sideways force to make it slow down in the sideways direction but also transfer some of that force to the forward direction so it keeps going in the direction it's now pointing.

I'm a bit confused as to how I go about doing this so any advice would be most welcome.

\$\endgroup\$

1 Answer 1

10
\$\begingroup\$

Disclaimer: There are probably other, and better ways to do this. Either way I'll share and describe the way I approached this problem a while back, which ended up working okay for me.

I've implemented a 2D top-down car game a couple of years ago for a university project, and if I remember correctly I used this article as a starting point, although I ended up simplifying it a lot, and dropped all of that "wheel" modeling stuff in favor of a single body for the car. What I did use however was something similar to the KillOrthogonalVelocity method which you can find there, to take care of applying lateral friction.

So, here's a little video of what it turned out like. There's a certain amount of sideways friction being applied which also depends on whether I'm using the handbrake button or not, and the car I used for the video also drifts significantly more than the others. This was controllable though. It also had a truck with zero sideways motion and very stiff controls.

I was never completely satisfied with the results, but it was enough for my needs. Bear in mind that I didn't base any of my physics on real vehicle movement or anything. I just tweaked and tried things out until It felt right.

Sideways Friction

So, to give a few details on the implementation, basically, when I adapted that method to my project, I added a variable which allowed me to control exactly how much of the lateral velocity I would kill, as a value between 0 and 1. This allowed me to fine tune the handling of the car and how much it could drift. Here's the method translated to XNA and simplified:

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;
}

As you can see I'm using vectors and linear algebra though, not trigonometry, so you'll have to adapt it to your needs. Both car.Forward and car.Right are normalized vectors pointing in that particular direction.

Throttle, Brakes, Steering

Other than that the only other relevant part was how I applied the forces to the car to make it move and steer:

  • Accelerating and braking was simple. Just a matter of applying a force in the direction the car was currently facing, or its inverse.
  • Steering on the other hand had a couple of tricks. Steering was done by applying a torque to the car (I used Box2D so this was a simple method call) but the power of that torque depended on a few factors, in particular:

    1. When breaking I increased the torque by 25% to make it possible to make sharper turns. if(braking || handbraking) torque *= 1.25
    2. When going in reverse, I also reversed the torque in order to get the correct controls. if(reverse) torque *= -1
    3. Finally, if the car was going under a certain speed threshold, I made it steer less than usual. if(speed < 2.0f) torque *= (speed / 4.0f)

Then just call the KillOrthogonalVelocity() method to adjust the final velocity and make it behave less like a spaceship and more like a car.

\$\endgroup\$
1
  • \$\begingroup\$ Thanks for the answer, just had a go at implementing your suggestion and it seems to be working really well. I'll definitely be trying out some of the other things you mentioned about steering. Thanks! \$\endgroup\$
    – pogo
    Jan 29, 2012 at 19:48

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .