Search code examples
javagame-physics

Mathematical Vectors and Rotations (Topdown java game dev - physics problem)


I've been working on a top down car game for quite a while now, and it seems it always comes back to being able to do one thing properly. In my instance it's getting my car physics properly done.

I'm having a problem with my current rotation not being handled properly. I know the problem lies in the fact that my magnitude is 0 while multiplying it by Math.cos/sin direction, but I simply have no idea how to fix it.

This is the current underlying code.

private void move(int deltaTime) {

double secondsElapsed = (deltaTime / 1000.0);// seconds since last update
double speed = velocity.magnitude();
double magnitude = 0;

if (up)
    magnitude = 100.0;
if (down)
    magnitude = -100.0;
if (right)
    direction += rotationSpeed * (speed/topspeed);// * secondsElapsed;
if (left)
    direction -= rotationSpeed * (speed/topspeed);// * secondsElapsed;

double dir = Math.toRadians(direction - 90);
acceleration = new Vector2D(magnitude * Math.cos(dir), magnitude * Math.sin(dir));

Vector2D deltaA = acceleration.scale(secondsElapsed); 
velocity = velocity.add(deltaA); 

if (speed < 1.5 && speed != 0)
    velocity.setLength(0);

Vector2D deltaP = velocity.scale(secondsElapsed); 
position = position.add(deltaP);

...
}

My vector class emulates vector basics - including addition subtraction, multiplying by scalars... etc.

To re-iterate the underlying problem - that is magnitude * Math.cos(dir) = 0 when magnitude is 0, thus when a player only presses right or left arrow keys with no 'acceleration' direction doesn't change.

If anyone needs more information you can find it at

http://www.java-gaming.org/index.php/topic,23930.0.html


Solution

  • Yes, those physics calculations are all mixed up. The fundamental problem is that, as you've realized, multiplying the acceleration by the direction is wrong. This is because your "direction" is not just the direction the car is accelerating; it's the direction the car is moving.

    The easiest way to straighten this out is to start by considering acceleration and steering separately. First, acceleration: For this, you've just got a speed, and you've got "up" and "down" keys. For that, the code looks like this (including your threshold code to reduce near-zero speeds to zero):

    if (up)
        acceleration = 100.0;
    if (down)
        acceleration = -100.0;
    
    speed += acceleration * secondsElapsed;
    
    if (abs(speed) < 1.5) speed = 0;
    

    Separately, you have steering, which changes the direction of the car's motion -- that is, it changes the unit vector you multiply the speed by to get the velocity. I've also taken the liberty of modifying your variable names a little bit to look more like the acceleration part of the code, and clarify what they mean.

    if (right)
        rotationRate = maxRotationSpeed * (speed/topspeed);
    if (left)
        rotationRate = maxRotationSpeed * (speed/topspeed);
    
    direction += rotationRate * secondsElapsed;
    
    double dir = Math.toRadians(direction - 90);
    velocity = new Vector2D(speed * Math.cos(dir), speed * Math.sin(dir));
    

    You can simply combine these two pieces, using the speed from the first part in the velocity computation from the second part, to get a complete simple acceleration-and-steering simulation.