Click here to Skip to main content
Email Password   helpLost your password?

Introduction

This is the first installment of a series of tutorials in which we aim to make a 3D Driving Simulation Game. With every successive tutorial we will try to make the game cooler by adding new features in graphics, physics and gameplay. The aim of this first tutorial is to simulate a car over an infinitely large plane. I know this is not exactly what we have in the real world. But we will get more realistic in later tutorials. For now imagine the world as a perfect plane with no obstacles.

Background

This article is not for the absolute beginner. A basic understanding of XNA Game Studio 2.0 is necessary. But If you are a beginner, I would suggest the following.

  1. Download and Install Microsoft Visual C# 2005 Express Edition, its SP1 Update, and XNA Game Studio 2.0. All these can be download free of cost from www.microsoft.com
  2. Go through the 'XNA Game Studio Documentation'. Especially the articles 'Your First Game: Microsoft XNA Game Studio in 2D' and 'Going Beyond: XNA Game Studio in 3D'. These tutorials are fairly easy to comprehend.
  3. Go through the Riemer's XNA Tutorial. Reading all the 3 tutorials will give you a very good understanding of XNA. But for now the first 2 tutorials are sufficient. The concept of Quaternions should be clearly understood.

Reasonable Knowledge of Newtonian Mechanics and Geometry is necessary to understand the formulas.

Using the code 

The application has been divided into three classes Game1, Stuff, Car . The class Stuff represents any material body than can be rendered on the screen. The class Car is a specialization of the Class Stuff which represents a Car. The class Game1 is the main application and uses objects of Stuff and Car.

Let us first understand the class Stuff. If you go through the code you will see that I have tried to encapsulate everything required to store information of any material body and render it on screen. I am only providing an overview of the member variable and function since the code is fairly straight forward.

Now for the most difficult part - understanding the class Car. There are two concepts at work. The first one is the effect of hitting the accelerator, releasing it, and braking on the cars motion. The second one is how the car turns when the steering is turned left or right.

The first concept. At any instant the car is in some gear represented by the variable gear. The speed of the vehicle determines the gear. We have the top speed at each gear stored in the variable topSpeeds. The top speed at gear x is also the minimum speed for gear x+1. The acceleration is different at each gear.

	public void Accelerate()
	{
	    free = false;

		if ((gear<7)&&(speed > topSpeeds[gear]))
	    {
	        gear++;                
	    }
	    if (gear == 0)
	    {
	        acceleration = accelerations[1];
	    }
	    else if (gear < 7)
	        acceleration = accelerations[gear];
	    else
	    {
	        gear = 6;
	        acceleration = 0;
	         speed = topSpeeds[6];
	    }
	}

Now when the brake is applied the effect is that a negative acceleration whose magnitude is the acceleration at that gear added to a constant as shown. Here you also have to consider the reverse gear and the maximum speed in reverse.

	public void Brake()
	{
	    free = false;

	    if((gear>0)&&speed<=topSpeeds[gear-1])
	    {
	        gear--;
	    }
	    if ((gear == 0) && (speed < -maxReverseSpeed))
	    {
	        acceleration = 0;
	        speed = -maxReverseSpeed;
	    }
	    else
	    {
	        acceleration = -accelerations[gear]-6.7f;              
	    }
	}

Also when the accelerator is released, even then a negative acceleration with magnitude same as acceleration at that gear has to be applied. And eventually the car comes at rest

	public void Free()
	{
	    free = true;

	    if ((gear>0)&&(speed < topSpeeds[gear - 1]))
	    {
	        gear--;
	    }
	          
	    acceleration = - accelerations[gear];         
	}

To determine the new position of car after every instant the following code is placed in the Update method.

	float speed = speed + acceleration * time;
	float dist = speed * time;
	Vector3 addVector = Vector3.Transform(new Vector3(0, 0, -1), rotation);
	position += addVector * dist; 

To make sure the car eventually comes to stop when neither accelerator nor brake is pressed this code is used:

	float newSpeed = speed + acceleration * time;
	if ((free == true) && (newSpeed * speed <= 0.0f))
	{
		gear = 1;
		acceleration = accelerations[gear];
		speed = 0.0f;
	}
	else
		speed = newSpeed;

Now let us understand how a car turns. When the driver steers left or right, the plane surface makes and angle theta with the body of the car as shown in figure. Theta should uniformly increase from to 0 to a Maximum Value. Also when the steering is left free theta should eventually become zero. The code for this is as follows:

	if (turn == 0)
	{
		float newAngle = steerAngle;
		if (steerAngle < 0.0f)
		{
			newAngle = steerAngle + time * steerSpeed;
		}
		else if (steerAngle > 0.0f)
		{
			newAngle = steerAngle - time * steerSpeed;
		}
		if (newAngle * steerAngle < 0.0f)
		{
			steerAngle = 0.0f;
		}
		else
			steerAngle = newAngle;
	}
	else
	{
		if (turn == -1)
		{
			float newAngle = steerAngle - time * steerSpeed;
			if (newAngle < -maxSteerAngle)
			{	
				steerAngle = -maxSteerAngle;
			}
			else
			{
				steerAngle = newAngle;
			}
		}
		else
		{
			float newAngle = steerAngle + time * steerSpeed;
			if (newAngle > maxSteerAngle)
			{
				steerAngle = maxSteerAngle;
			}
			else
			{
				steerAngle = newAngle;
			}
		}                
	}

Now that we have understood how the tire turns, let us figure out how the car turns. Look at the figure carefully. 

You will at once understand what the constants HD,VD and L represent.O is the origin of the 3D Model. We assume that the car will rotate about the point marked "Center Of Turning" with radius r. The value of r can be calculated using trignometry

float x = (VD / Math.Abs((float)Math.Tan(steerAngle)) + HD / 2);
float r = (float)Math.Sqrt(x * x + L * L);

Now we have the radius. The angle by which the car rotates can be found out and corresponding Quaternion is created.

float theta = speed * time / r;
if (steerAngle < 0.0f)
theta = -theta;
rotation = rotation * Quaternion.CreateFromAxisAngle(new Vector3(0, -1, 0), theta);

New position of car can be determined as follows.

speed = speed + acceleration * time;
float dist = speed * time;
Vector3 addVector = Vector3.Transform(new Vector3(0, 0, -1), rotation);
position += addVector * dist;

The rest of the code is pretty much straight forward.

I would like to thank my friend Tarang Bakshi for his help with the game physics and ideas.

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
Generalhai i have a query
Lakshmi sravani
4:09 5 Dec '09  
hai AmitDey

i saw ur code for driving simulator its very help full. But have a doubt hope it will be clarified. I am doing a project on 2D Boat Simulation my query is with out using XNA can we give movement to a object that means by using csharp only can we give simulation to the object. As it is boat i have to show the docking of it also thats why i am asking this question.

expecting anwser from you.

regards sravani
Generalcrashed ,cause a file didn't founded
ehsan_kh
6:40 13 Oct '08  
hi
your sample application crashed with the following error :
An Unhandled Exception ('system.IO.FileNotFoundException')Occured in simcar.exe [520].
bad sample ,boy!Confused
GeneralRe: crashed ,cause a file didn't founded
AmitDey
8:23 13 Oct '08  
Do you have XNA Game Studio 2.0 Installed ?
GeneralCan't get the sample to work
yassir hannoun
11:36 14 Sep '08  
i have visual studio 2008 with xna studio 3.0 but i can't load the project ideas ??
GeneralRe: Can't get the sample to work
Greeeg
11:59 14 Sep '08  
It's a XNA 2.0 project. You can convert it to XNA 3.0 though, see this link[^].

regards
GeneralRe: Can't get the sample to work
yassir hannoun
12:48 14 Sep '08  
did not work
GeneralRe: Can't get the sample to work
AmitDey
20:53 14 Sep '08  
If nothing else work. You can alawys try Visual Studio 2005 and XNA Game Studio 2.0
Generali try to run, but don't works...
Sergey Alexander Gynech
11:34 14 Sep '08  
So, i just download the demo, and he doesn't work, what are the requeriments? i need to install something extra to run?
I'm using windows xp sp2 with directx 9 installed and 3d card.
GeneralRe: i try to run, but don't works...
Greeeg
12:02 14 Sep '08  
Sergey Alexander Gynech wrote:
what are the requeriments? i need to install something extra to run?


See this link[^] for more information.

regards
JokeOooooo......
The Dogcow Farmer
10:57 14 Sep '08  
Looks good. Is that a Nissan I see?

Chuck Norris has the greatest Poker-Face of all time. He won the 1983 World Series of Poker, despite holding only a Joker, a Get out of Jail Free Monopoloy card, a 2 of clubs, 7 of spades and a green #4 card from the game UNO.
In the movie "The Matrix", Chuck Norris is the Matrix. If you pay close attention in the green "falling code" scenes, you can make out the faint texture of his beard.
Chuck Norris actually owns IBM. It was an extremely hostile takeover.

GeneralRe: Oooooo......
Greeeg
11:02 14 Sep '08  
The Dogcow Farmer wrote:
Is that a Nissan I see?


Yes, a Nissan 350Z[^].
GeneralGood article, some suggestions
Greeeg
10:41 14 Sep '08  
Hi,

first of all I think this is a good article, so I'm providing some suggestions/constructive criticism here. I'm driving a car myself and have been playing racing simulations (GTL/GTR/GTR2/Race07) for quite some time now. I do not have a good understanding in car physics though.

1) display the current gear
2) provide a sound that resembles the current rev
3) it would be cool if the acceleration was not only based on the gear but also the current rev, and applying the throttle/break via the XBox thumbstick/trigger buttons (also available for Windows) would also add to the realism
5) I'd like to see the physics being based on a realistic gear transmission ratio, that would also add to the realism
4) it seems that the car can turn/spin rather quickly, even at a very low speed
5) the grid is actually not infinite, it ends after some distance Wink

I added some code to display the current gear and speed on the display, here they are:

DrawInfo() method in Car.cs:

public void DrawInfo(SpriteBatch spriteBatch)
{
spriteBatch.DrawString(font, "Steering angle: " + steerAngle.ToString(), Vector2.Zero, Color.White);

spriteBatch.DrawString(font, "Gear: " + gear.ToString(), new Vector2(0, 16), Color.White);

spriteBatch.DrawString(font, "Speed " + speed.ToString(), new Vector2(0, 32), Color.White);
}


(Not very optimized, ideally you should put the Vector and string allocations somewhere else to minimize work for the garbage collector, especially on the XBox.)

Uncommenting the lines in the Draw() method to display the info doesn't work due to some renderstates not being reset[^].
Here's a version that fixes this problem:

Draw-method in Game1.cs:

protected override void Draw(GameTime gameTime)
{
device.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.DarkSlateBlue, 1.0f, 0);

device.RenderState.FillMode = FillMode.Solid;
car.Draw();

device.RenderState.FillMode = FillMode.WireFrame;
mesh.Draw();

device.RenderState.FillMode = FillMode.Solid;
spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.SaveState);
car.DrawInfo(spriteBatch);
spriteBatch.End();

base.Draw(gameTime);
}


regards
GeneralRe: Good article, some suggestions
AmitDey
20:59 14 Sep '08  
Wow thanks a lot for your interest and involvement. To reply to some of your points - I am planning to relase a series of tutorials about this. So this one is pretty basic. Will add more features in later tutorials.

I am not very good in physics either. So hoping to have more realism next time.

And thanks a lot for your dispaying info code. It helps a lot.
GeneralRe: Good article, some suggestions
AmitDey
0:48 15 Sep '08  
BTW I said the plane is infinite. Didn't say anything about the grid. Poke tongue


Last Updated 14 Sep 2008 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010