12
\$\begingroup\$

I have goggled how to do this and found this http://www.helixsoft.nl/articles/circle/sincos.htm I have had a go at it but most of the functions that were showed didn't work I just got errors because they didn't exist. I have looked at the cos and sin functions but don't understand how to use them or how to get the car movement working correctly using vectors. I have no code because I am not sure what to do sorry.

Any help is appreciated.

EDIT:

I have restrictions that I must use the TL engine for my game, I am not allowed to add any sort of physics engine. It must be programmed in c++. Here is a sample of what i got from trying to follow what was done in the link I provided.

if(myEngine->KeyHeld(Key_W))
    {
        length += carSpeedIncrement;
    }
    if(myEngine->KeyHeld(Key_S))
    {
        length -= carSpeedIncrement;
    }
    if(myEngine->KeyHeld(Key_A))
    {
        angle -= carSpeedIncrement;
    }
    if(myEngine->KeyHeld(Key_D))
    {
        angle += carSpeedIncrement;
    }

    carVolocityX = cos(angle);
    carVolocityZ = cos(angle);

    car->MoveX(carVolocityX * frameTime);
    car->MoveZ(carVolocityZ * frameTime);
\$\endgroup\$
3
  • \$\begingroup\$ Check this site out for steering behaviors: red3d.com/cwr/steer \$\endgroup\$
    – House
    Apr 5, 2012 at 17:57
  • \$\begingroup\$ You need to define "realistic car movement" \$\endgroup\$ Apr 6, 2012 at 10:35
  • 1
    \$\begingroup\$ I assume your angle comes from the steering wheel, perhaps. The length should be the magnitude of your velocity. So the last code snippet could be something on the lines of: carVecloityX = length* cos(angle); , carVelocityZ = length *sin(angle);, apart from that, please tell what your input is and how the car should behave. Right now, it should steer in the ground plane, but again, this is not at all general. There you just made us of a crude Euler integration step.. \$\endgroup\$
    – teodron
    Apr 6, 2012 at 11:16

2 Answers 2

25
\$\begingroup\$

It's not that hard to create a fairly good car movement (but this post will be pretty long). You'll need to "simulate" a couple of basic forces to make the car move physically plausible.

(All the code samples are pseudocode.)

Acceleration

First, you'll obviously need acceleration. Something as simple as the following line would do:

acceleration_vector = forward_vector * acceleration_input * acceleration_factor
  • forward_vector — A vector pointing in the same direction as the car.
  • acceleration_input — The input should be in the interval [-1, 1].
  • acceleration_factor — The value of the acceleration (pixels / second^2, or whatever your units are).

Steering

Steering is also fairly simple. In principle, what you will do is to rotate the forward vector of the car as to make it point in some other direction.

steer_angle = steer_input * steer_factor
new_forward_vector = rotate_around_axis(forward_vector, up_vector, steer_angle)

You might encounter a complication here, however. If your input is through a keyboard, its value will be either -1 or 1 which means your car would turn instantaneously. You can fix this using a very simple linear interpolation (lerping):

 amount = time_since_last_frame * steer_lerp_factor
 forward_vector = lerp(forward_vector, new_forward_vector, amount)

The amount should depend on time such that your movement does not depend on your frame rate. The amount should be between [0, 1] and the smaller it is, the smoother the transition between the old and new vectors will be.

(At this point you will find that the car will steer even if it is standing still. To prevent that, multiply steer_angle by current_speed / max_speed, where max_speed is a constant defined by you.)

Moving

Now we'll apply the acceleration and move the car a certain number of pixels based on its velocity, acceleration, and on steering. We will also want to limit the car's speed such that it doesn't end up moving infinitely fast.

current_speed = velocity_vector.norm()
if (current_speed < max_speed)
{
    velocity_vector += acceleration_vector * time_since_last_frame
}

position_vector += velocity_vector * time_since_last_frame

Your car is now sliding

If I'm right, your car should now appear to be sliding whenever you are turning as if it was on ice. This is because there is no friction. On a real car there a high lateral friction (due to the wheels not being able to rotate sideways :P ).

You will need to reduce the lateral velocity. By not reducing it completely you can also make the car appear to be drifting.

 lateral_velocity = right_vector * dot(velocity_vector, right_vector)
 lateral_friction = -lateral_velocity * lateral_friction_factor 

Since we're talking about friction, you might also want to have a force (of friction) that reduces your velocity such that when you stop accelerating, your car will eventually stop.

 backwards_friction = -velocity_vector * backwards_friction_factor

Your code for moving the car should now look like this:

// Friction should be calculated before you apply the acceleration
lateral_velocity = right_vector * dot(velocity_vector, right_vector)
lateral_friction = -lateral_velocity * lateral_friction_factor
backwards_friction = -velocity_vector * backwards_friction_factor
velocity_vector += (backwards_friction + lateral_friction) * time_since_last_frame


current_speed = velocity_vector.norm()
if (current_speed < max_speed)
{ 
    velocity_vector += acceleration_vector * time_since_last_frame
}

position_vector += velocity_vector * time_since_last_frame

Closing notes

I mentioned how you should apply lerping to steering; I think you might need to do the same thing for acceleration and possibly for the steer angle as well (you will have to store their values from the previous frame and lerp from that). Also all the vectors relative to the car (forward, right, up) should be of length 1.

Also, friction is a bit more complicated than I showed here. You should always make sure that its length is never greater than that of the acceleration needed to make the car stop (otherwise friction would make the car move the opposite way). So you should have something like:

dt = time_since_last_frame
backwards_friction.resize(min(backwards_friction.norm(), velocity_vector.norm() / dt))
lateral_friction.resize(min(lateral_friction.norm(), lateral_velocity.norm() / dt))
\$\endgroup\$
1
  • \$\begingroup\$ Wow, this is a great answer! \$\endgroup\$
    – ezolotko
    Dec 17, 2013 at 12:17
0
\$\begingroup\$

Judging from your question, I am going to assume you are relatively new to programming (which is a-ok btw!). I would suggest to use existing frameworks as realistic car simulation is one of the hardest aspects of physics to get right.

You did not mention 2D/3D restrictions so I am going to go ahead and suggest you download Havok SDK (free for non-commercial use) and get a simple demo up and running (they actually have demos that run out of the box [get compiled on your system, all the code is there], you don't have to do anything to get it to compile... just open the project and hit build).

Once you have some idea on the behind the scenes aspects of car physics (although you won't see the actual implementation of the physics, that is hidden, you will get to see the interfaces), I believe you will be in a better position to get it right when you do start on your own.

I also asked a similar question not too long ago. The links in there may help as well. And here's another link.


After looking at your edit, it seems you are looking to simply change the velocity of the car depending on the calculated angles (that is not realistic btw, so you should change the original question to reflect that). If the angles are part of the question (that you can't change) and you have to use the angles to calculate the new velocity, then go with what @teodron put in the comments.

Another way is to use vectors only. There are multiple approaches using vectors, I am going to present one.

A velocity is direction * magnitude (where magnitude is speed and direction is a normalized vector). Calculate the car's current speed and direction. Take the direction and add a vector (let's call it D') to it that is perpendicular to it. This will change the car's velocity. No angles to mess around with (although you can use angles to determine the length of the perpendicular vector which can be you turn factor [see below] )

How to calculate D': To find the perpendicular vector, take the direction of the original velocity, cross it with the direction vector coming towards the screen where the order you cross the vectors in determines the direction of the perpendicular vector. Then multiple this perpedicular factor with some turn factor which determines how fast the car it turning.

\$\endgroup\$
4
  • \$\begingroup\$ I would but I am no allowed to use a physics engine, the game is 3D and all I need to change is the X and Z vectors I just need to work out what they are. \$\endgroup\$
    – bobthemac
    Apr 5, 2012 at 14:50
  • \$\begingroup\$ @bobthemac: Is this a homework question? If yes, edit your question to point out the restrictions you have and maybe post some relevant code so that we have something to build up on. Btw, the last link may be what you are looking for in terms of understanding the functionality. \$\endgroup\$
    – Samaursa
    Apr 5, 2012 at 14:51
  • \$\begingroup\$ I have added the information you requested and looked at the links provided but still don't understand it. \$\endgroup\$
    – bobthemac
    Apr 5, 2012 at 16:07
  • \$\begingroup\$ @bobthemac: See my edit \$\endgroup\$
    – Samaursa
    Apr 6, 2012 at 17:25

You must log in to answer this question.

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