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))
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\$