Sign in to follow this  

Help with simple 2D car physics

This topic is 3587 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello there, I'm currently a little confused how to implement simple 2D car physics, now I'd like to emphasize simple here. I've already managed to implement acceleration (I think!) but my car just does this when you accelerate: - acceleration Now I'm presuming this is just demonstrating the linear nature of acceleration over time. My question is, how do I implement turning/steering? A lot of guides (there's one on this website) talk about implementing 4 wheels, I don't wish to do that just yet, that's perhaps a little....too realistic for my needs. I just want something that can accelerate and steer... Any help would be appreciated!

Share this post


Link to post
Share on other sites
Assuming you have a fully defined vector class. What you would do is at some interval, update the car's postion based on it's velocity. Just make sure to adjust the car's velocity beforehand by its current acceleration vector.



struct Vectory2D {
int x;
int y;
// Define your operators here
};

class Car {
public:
Vector2D m_acceleration;
Vector2D m_velocity;
Vector2D m_position;

float m_facing;
void Turn(float degrees);
};

void Turn(float degrees) {
m_facing += degrees;
Matrix transform;
transform.Identity();
transform.Rotate(DEG_TO_RAD(m_facing));
m_velocity *= transform;
}

void Car::UpdatePosition(DWORD elapsed) {
m_velocity += (m_accelaration * elapsed);
m_position += (m_velocity * elapsed);
}






To make it change direction, apply a rotation to the velocity vector.



int main(int argc, char** argv)
{
Car racer;
racer.m_position = Vector(ScreenWidth / 2, ScreenHeight / 2); // Its inital
// postion is in the middle of the screen. Assuming a screen size of
// 640x480 its current position is:
// {320, 240}
racer.m_velocity = Vector(1,-1); // Car will initially head to the upper right

racer.UpdatePosition(1); // Car will now move from its initial position of {320,240} to {321,239}
// which puts it one pixel closer to the upper right corner as you've depicted
racer.Turn(90); // Turns the car 90 degrees to the left

//m_velocity should now be {-1, -1}

racer.UpdatePosition(1);
// m_postion should now be {320, 238} and if allowed to continue is now
// heading to the upper left.

racer.Turn(90); // this will turn the car another 90 degreens to the left
// for a total of 180 degrees from its inital velocity direction

// m_velocity should now be {-1, 1};

racer.UpdatePosition(1);
// m_position should now be {319, 239} and if allowed to continue is now
// heading to the lower left.

}





There are plenty of optimizations you can make but I've omitted them for clarity. Basically, you car travels in the direction of its velocity. To change direction, just keep modifying it's velocity vector.

[Edited by - Tenbatsu on February 13, 2008 8:36:41 PM]

Share this post


Link to post
Share on other sites
Thankyou for the help people, but I'm still a little confused as to what you are getting at (sorry)

Tenbatsu I implemented your code, but got stuck when it came to using matrices to transform the vector, I haven't got a matrix class and when attempting to implement a quick one, this line of code threw me off

m_velocity *= transform;



What does that do?

Games4TheFuture thankyou for the reply, but could you be kind to elaborate on what you mean? How do I put those values so it alters the position of my car?

K_J_M - Thankyou for the reply, I've had a quick glance at the downloads and there's a whole breadth of information there! Thankyou!

Forgive me, I'm a little poor when it comes to maths at times so any help would be appreciated.

Share this post


Link to post
Share on other sites
Quote:
Original post by djhworld
m_velocity *= transform;

What does that do?

I think that's equivalent to m_velocity = m_velocity * transform; which is taking the product of a vector and a matrix, and assigning it to m_velocity. That matrix is a rotation matrix, used to rotate the vector by a certain number of degrees (specified in code above) around its origin.

I might be wrong about the order of multiplication... Shouldn't it be matrix by vector instead? Or does it not matter? I can't really remember this, maybe someone else can answer.

Hope that helps. You can find some useful info here.

Share this post


Link to post
Share on other sites
shurcool

Thank you for the reply, I think I've implemented a rotation matrix, but does this mean I have to rotate all three axis?

How would I go about doing this? At the moment it just rotates along the x-axis, which I believe is incorrect

void Matrix::rotate(float rads) {
m[1][1] = cos(rads);
m[1][2] = -sin(rads);
m[2][1] = sin(rads);
m[2][2] = cos(rads);
}

Share this post


Link to post
Share on other sites
Here goes.

Lets say:
xPos is the current locaion of the car in the X direction
yPos is the current location of the car in the Y direction

V is the distance the car can travel in a cycle, for example it could corespond to 5 pixels in each cycle.

To find the new location of the car you need to also know the direction the car is facing. I'm calling this angle A for now. It is the measure of the angle from the positive x axis to the direction the car is facing.

In C++ the code would look something like this:

int A; // If the car is facing right it would be zero.
// Update this angle by adding to it as the car turns left.
// Subtract from it as the car turn right.
int xPos, yPos; // Stores the cars position.

void UpdatePosition()
{
int XVelocity = V * cos(A);
int YVelocity = V * sin(A);

xNewPos = xPos + xVelocity;
yNewPos = yPos + yVelocity;
}

If you have any qestions PM me.

Share this post


Link to post
Share on other sites
Hi there, thanks for the help Games4TheFuture, I reckon I've implemented some of the ideas you've expressed, as well as everyone else in this thread.

I'm currently having a few little problems, especially when turning. Here is my code: -

void raceControl::accelerate(int ms) {
float f = raceControl::theCar.forces / raceControl::theCar.mass;
raceControl::theCar.r_acceleration.x = f;
raceControl::theCar.r_acceleration.y = f;
raceControl::theCar.r_acceleration.z = f;

if(raceControl::theCar.a) {
//Throttle pressed
raceControl::theCar.r_velocity += (raceControl::theCar.r_acceleration * ms)/1000.0f;
raceControl::theCar.r_position += (raceControl::theCar.r_velocity * ms)/1000.0f;

}
else if(raceControl::theCar.b) {
//Throttle released
raceControl::theCar.r_velocity -= (raceControl::theCar.r_acceleration * ms)/1000.0f;
raceControl::theCar.r_position += (raceControl::theCar.r_velocity * ms)/1000.0f;

if(raceControl::theCar.r_velocity.vecMagnitude() < 0.01) {
//stop car once speed reaches too low
raceControl::theCar.r_velocity.reset();
raceControl::theCar.r_acceleration.reset();
}
}

f = 0.0;
}

void raceControl::updateScene(int ms) {
//update scene
raceControl::accelerate(ms);

if(raceControl::theCar.c) {
//if steering wheel used (keys left and right make r_angle +1, -1 respectively
raceControl::theCar.Turn(ms);
}
}

void cCar::Turn(int ms) {
r_facing += r_angle;
Matrix transform;
transform.identity();
transform.rotate(r_facing*PI/180.0f);
r_velocity = transform * r_velocity;
r_facing = 0.0;
}




Now all that works great, until you let go of the steering wheel, then the car just accelerates away and it's hard to stop. Any ideas? There's probably something leaking in my code to throw the maths off a bit but what should happen is the car should slow down (if the throttle is off) as it turns the corner! If you just simply accelerate (from the start) it does exactly the same thing as it should as the image in the first post, it accelerates then decelerates depending on the status of the throttle.

It all goes wrong when you turn a corner though, At the moment is sort of does this...(excuse the poor photoshop)

race

Any ideas? Any help would be appreciated.

Share this post


Link to post
Share on other sites
Okay ignore the previous post.

I'm currently having difficulties implementing braking, whenever I try to make my car brake it doesn't seem to affect it, here is my code: -

Physics stuff: -

void raceControl::updateScene(int ms) {
float sn = sin(raceControl::theCar.r_angle);
float cs = cos(raceControl::theCar.r_angle);
// transform velocity in world reference frame to velocity in car reference frame
velocity.x = cs * raceControl::theCar.r_velocity.y + sn * raceControl::theCar.r_velocity.x;
velocity.y = -sn * raceControl::theCar.r_velocity.y + cs * raceControl::theCar.r_velocity.x;
// weight = half car mass times 1G (=9.8m/s^2)
weight = raceControl::theCar.mass * GRAVITY * 0.5;
// longtitudinal force
f_traction.x = 100*(raceControl::theCar.throttle - raceControl::theCar.brake*raceControl::sgn(velocity.x));
f_traction.y = 0;

// Forces and torque on body

// drag and rolling resistance
resistance.x = -( RESISTANCE*velocity.x + DRAG*velocity.x*abs(velocity.x) );
resistance.y = -( RESISTANCE*velocity.y + DRAG*velocity.y*abs(velocity.y) );

// sum forces
force.x = f_traction.x + sin(raceControl::theCar.steeringangle) * resistance.x/weight;
force.y = f_traction.y + cos(raceControl::theCar.steeringangle) * resistance.y/weight;

// Acceleration

// Newton F = m.a, therefore a = F/m
acceleration.x = force.x/raceControl::theCar.mass;
acceleration.y = force.y/raceControl::theCar.mass;



// Velocity and position

// transform acceleration from car reference frame to world reference frame
acceleration_wc.x = cs * acceleration.y + sn * acceleration.x;
acceleration_wc.y = -sn * acceleration.y + cs * acceleration.x;
// velocity is integrated acceleration
//
raceControl::theCar.r_velocity.x +=(acceleration_wc.x * ms)/1000.0f;
raceControl::theCar.r_velocity.y += (acceleration_wc.y * ms)/1000.0f;

raceControl::theCar.r_position.x += (raceControl::theCar.r_velocity.x * ms)/1000.0f;
raceControl::theCar.r_position.y += (raceControl::theCar.r_velocity.y * ms)/1000.0f;

if(raceControl::theCar.steeringangle!=0.0) {
raceControl::theCar.Turn(ms);
}
}

void cCar::Turn(int ms) {
r_facing += steeringangle;
Matrix transform;
transform.identity();
transform.rotate(PI * (r_facing) / 180.0f);
r_velocity = transform * r_velocity;
r_angle = r_facing;
r_facing = 0.0;
}



Control stuff:-

case GLUT_KEY_UP:
{
if(theRace.theCar.throttle < 10) {
theRace.theCar.throttle += 0.1;
}

break;
}

case GLUT_KEY_DOWN:
{
if(theRace.theCar.throttle > 0.0) {
theRace.theCar.throttle -= 0.1;
}

break;
}
case GLUT_KEY_LEFT:
{
if(theRace.theCar.steeringangle > -M_PI/4.0) {
theRace.theCar.steeringangle -= M_PI/32.0;
}
break;
}
case GLUT_KEY_RIGHT:
{
if(theRace.theCar.steeringangle < M_PI/4.0) {
theRace.theCar.steeringangle += M_PI/32.0;
}
break;
}

case GLUT_KEY_END:
{

theRace.theCar.brake = 150;
theRace.theCar.throttle = 0;
break;
}




When I brake nothing seems to affect it, the car just continues travelling at it's current speed, even if the throttle is set to 0!

I reckon it's down to this line of code, I used it from some source code taken from kjmsoftware.


f_traction.x = 100*(raceControl::theCar.throttle - raceControl::theCar.brake*raceControl::sgn(velocity.x));



Any help would be appreciated.

Share this post


Link to post
Share on other sites

This topic is 3587 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this