Jump to content
  • Advertisement
Sign in to follow this  
stuhow

Vehicle Dynamics and Physics

This topic is 3258 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

Hi Guys, I am creating a top down racing game in Flash and AS3. I am following Marco Monsters physics tutorial and moving forward everything works a treat. However when I turn the car acts more like a boat or as if it is driving on ice. This is before I have even added any lateral forces to the car, yet it is behaving as if it has these forces acting on it. You can play a demo at: http://www.kokodev.co.uk/race_test/ Below is my code, can anyone shed any light on this. I have created a Vector class at the bottom of the code to control x and y movement.

package 
{
	import adobe.utils.ProductManager;
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import fl.motion.*
	
	import console.math.Trig;
	
	/**
	 * ...
	 * @author Stuart Howarth
	 */
	public class Car extends Sprite
	{
		/*
		 * THIS CLASS CREATES A BLIT CAR AND CHECKS COLLISIONS AND REACTS ACCRODINGLY
		 */
		
		public var _carBmpData:BitmapData;
		public var _carBmp:Bitmap = new Bitmap(_carBmpData);
		
		//Engine Variables

		private var _driver = new Driver();


		/*
		 * ALL NUMBERS ARE IN S.I UNITS
		 */
		
		//Car Direction Vectors
		private var _vLong:Vector = new Vector(0,0); //Longitude vector (Velocity of the vehicle in a forward motion)
		private var _vLat:Vector = new Vector(0, 0); //Latitude Vector (Velocity of the vehicle in a sideways motion
		private var _vAcceleration = new Vector(0, 0) // Acceration vector of the car
		
		
		private var _intSpeed:Number = 0;
		
		//Forces
		private var _fTraction:Vector = new Vector(0,0); //Traction vector
		private var _fDrag:Vector = new Vector(0, 0); //Air Resistance Vector
		private var _fRollRes:Vector = new Vector(0, 0); //Rolling resistance vector
		private var _fLong:Vector = new Vector(0, 0); //Longitudinal force, this is what accelerates & decellerates the car
		
		private var _fTorque:Number = 0;
		
		private var _cDrag:Number = .5; //Drag Coefficient or Aerodynamics, Typical values range between 0 and 1, A corvette is 0.3.
		private var _cRollRes:Number = 15 //Rolling resistance, typically is 30x larger than _cDrag
		
		private var _cMass:Number = 600; //Weight of the carin KGs
		
		
		
		//Car Setup
		private var _intEngineForce:Number =100;
		private var _intBrakingForce:Number = 120;
		private var _intReverseForce:Number = 30;
		
		private var _engineStatus:int = 0; // Status of the engine, 0 = Idle, 1 = Accelerate Forward, 2 = Reverse
		private var _carHeading:Vector = new Vector(0, 0);
		
		private var _carWheelBase = 20;
		
		//Wheel Setup
		private var _intWheelMass = 75; //Weight of the wheel in KGs
		private var _intWheelRadius = .33 //Radius of the wheel in Meters
		private var _intWheelInertia = 0;
		private var _intWheelVelocity = 0;
		
		//Cornering
		private var _intSteeringAcceleration:Number = 10 //Speed the wheels turn in degrees per timestep/frame
		private var _intSteeringAngle:Number = 0; //Angle the wheel is facing in degrees relative to the car.
		private var _intSteeringAngleMax:Number = 30; //Maximum angle the wheels can face
		private var _intSteeringForce:Number = 0.7//This number is used to automatically returns the wheels to their straight position
		private var _isSteeringIdle:Boolean = true; //If this value is true then _intSteeringForce is acted on the steering angle to straighten the car out
		
		private var _intAngularVelocity:Number = 0;  //Speed at which the car turns in radiands per second/frame
		
		
		private var _intCorneringRadius = 0; //Cornering radius
		
		public function Car()
		{
			_driver.addKey(38, accelerate);
			_driver.addKey(40, reverse);
			_driver.addKey(37, steerLeft);
			_driver.addKey(39, steerRight);
			addEventListener(Event.ENTER_FRAME, controlCar);
			
		}
		
			private function controlCar(evt:Event)
		{
			//Sideways/Steering Motion
			correctSteering();
			calculateSteering();
			
			//Forward Motion
			calculateEngineForces();
			calculateLongitudeForces();
			calculateWheelVelocity();

			_engineStatus = 0; 
		}	
		
	
		private var _leftWheel:Sprite;
		private var _rightWheel:Sprite;
		
		public function createCarBlit(width:int, height:int, colour:uint)
		{
			_carBmpData =  new BitmapData(width, height, false, colour);
			_carBmp = new Bitmap(_carBmpData);
			_carBmp.x = -10;
			_carBmp.y = -5;

			buildWheels();
			
			this.x = 500;
			this.y = 500;
			
			addChild(_carBmp);
			addChild(_leftWheel);
			addChild(_rightWheel);
			
			this.rotation = 0;
			
			calculateWheelInertia()
		}
		private function buildWheels()
		{
			var wheel:BitmapData = new BitmapData(6, 3, false, 0xff0000);
			
			var wheelBitmap:Bitmap = new Bitmap(wheel);
			wheelBitmap.x = -wheelBitmap.width / 2;
			wheelBitmap.y = -wheelBitmap.height / 2;
			
			_leftWheel = new Sprite();
			_leftWheel.x = 5
			_leftWheel.y = -5;
			_leftWheel.addChild(wheelBitmap);
			
			wheelBitmap = new Bitmap(wheel);
			wheelBitmap.x = -wheelBitmap.width / 2;
			wheelBitmap.y = -wheelBitmap.height / 2;

			_rightWheel  = new Sprite();
			_rightWheel.x = 5
			_rightWheel.y = 5;
			_rightWheel.addChild(wheelBitmap);
		}
		
		/***********************************************************************************
		 * LONGITUDE FORCES - ACCELERATION/REVERSE
		 ***********************************************************************************/
		
		private function accelerate():void{ _engineStatus = 1; }
		private function reverse():void { _engineStatus = 2;}
		 
		private function calculateEngineForces()
		{
			//The car heading is based on the car moving forward by 1 pixel. This gives us the unit heading vector
			var carRotationRad =  newRadian(this.rotation)
			_carHeading.x = Trig.findAdjascentLength(carRotationRad, 1);
			_carHeading.y = Trig.findOppositeLength(carRotationRad, 1);		

			
			switch(_engineStatus)
			{
				case 0:
					//Idle engine
					_fTraction.x = 0;
					_fTraction.y = 0;
				break;
				case 1:
					//Accelerating
					_fTraction.x = _carHeading.x * _intEngineForce;
					_fTraction.y = _carHeading.y * _intEngineForce;
					
				break;
				case 2:
					//Braking/Reverse
					var brakingForce = _intBrakingForce;
					if (_intSpeed <= 0) brakingForce = _intReverseForce;

					_fTraction.x = -_carHeading.x * brakingForce;
					_fTraction.y = -_carHeading.y * brakingForce;
				break;
			}

		}
		
		private function calculateLongitudeForces()
		{
			_intSpeed = Math.sqrt(Math.pow(_vLong.x, 2) + Math.pow(_vLong.y, 2));
			
			_fTorque = _intSpeed * _intEngineForce;

			//Calculate total air resistance force
			_fDrag.x = -_cDrag * _vLong.x * _intSpeed;
			_fDrag.y = -_cDrag * _vLong.y * _intSpeed;
			
			//Calculate total rolling resistance force
			_fRollRes.x = -_cRollRes * _vLong.x;
			_fRollRes.y = -_cRollRes * _vLong.y;
			
			
			//Calculate total longitude force
			_fLong.x = _fTraction.x + _fDrag.x + _fRollRes.x;
			_fLong.y = _fTraction.y + _fDrag.y + _fRollRes.y;
						
			_vAcceleration.x = _fLong.x / _cMass;
			_vAcceleration.y = _fLong.y / _cMass;
			
			_vLong.x += _vAcceleration.x;
			_vLong.y += _vAcceleration.y;

			this.x += _vLong.x;
			this.y += _vLong.y;
		}
		
		/*
		 * WHEELS SETTERS AND GETTERS
		 */
		public function set wheelMass(val):void { _intWheelMass = val; calculateWheelInertia(); }
		public function set wheelRadius(val):void { _intWheelRadius = val; calculateWheelInertia();}
		private function calculateWheelInertia()
		{
			_intWheelInertia = _intWheelMass * Math.pow(_intWheelRadius, 2) / 2;
		}
		
		private function calculateWheelVelocity()
		{
			var angularAcceleration = _fTorque / _intWheelInertia;
			_intWheelVelocity = angularAcceleration;
		}
		
		/***********************************************************************************
		 * CORNERING
		 ***********************************************************************************/
		public function steerLeft(){steerWheels( -_intSteeringAcceleration);}
		public function steerRight() { steerWheels( _intSteeringAcceleration); }
		
		private function steerWheels($val:Number)
		{
			_isSteeringIdle = false;
			var newSteerDirection = _intSteeringAngle + $val	
			
			if (Math.abs(newSteerDirection) < _intSteeringAngleMax)
			{
				_intSteeringAngle = newSteerDirection
			}
			else
			{
				$val > 0 ? _intSteeringAngle = _intSteeringAngleMax : _intSteeringAngle = -_intSteeringAngleMax;
			}			
		}
		
		private function correctSteering()
		{
			/*
			 * This function is used to correct the steering if no keys are pressed
			 */
			
			if (_isSteeringIdle)
			{
				_intSteeringAngle *= _intSteeringForce
				if (_intSteeringAngle < 0.1 && _intSteeringAngle > -0.1)_intSteeringAngle = 0;
			}
			_isSteeringIdle = true;
		}
		 
		private function calculateSteering()
		{		
			_intCorneringRadius = _carWheelBase / Math.sin(newRadian(_leftWheel.rotation));
			
			if(_intCorneringRadius == Infinity){_intCorneringRadius = 99999}
			
			_intAngularVelocity = _intSpeed / _intCorneringRadius;
			
			_leftWheel.rotation = _rightWheel.rotation =_intSteeringAngle
			
			this.rotation += newDegree(_intAngularVelocity);
		}
		
		
		/***********************************************************************************
		 * GENERIC ESSENTIAL FUNCTIONS
		 ***********************************************************************************/
		public function newRadian($Degree):Number
		{
			return Trig.convertToRadian($Degree);
		}
		public function newDegree($Radian):Number
		{
			return Trig.convertToDegree($Radian);
		}
		
		
	}
	
}
import flash.geom.Point;

class Vector extends Point
{
	public function Vector($x, $y)
	{
		super.x = $x;
		super.y = $y;
	}
}

Any help would be appreciated. Cheers Stu [Edited by - stuhow on October 21, 2009 12:11:57 PM]

Share this post


Link to post
Share on other sites
Advertisement
I am treating the whole car effectivly as one wheel. I put the front wheels on so I could correctly see the direction the steering wheel is facing.If it is a problem I could put rear wheels on but they would purely be aesthetic.

Share this post


Link to post
Share on other sites
Quote:
Original post by stuhow
Does anybody have any suggestions??

Cheers
Stu


Figure out how to use the source tags. Please. They look like:
<source lang="cpp">C++ code goes here</source>

Only with [] brackets instead of <> brackets.

Share this post


Link to post
Share on other sites
Quote:
Original post by Numsgil
Figure out how to use the source tags. Please. They look like:
<source lang="cpp">C++ code goes here</source>

Only with [] brackets instead of <> brackets.


This is funny... I've been here on-and-off since forever (and using source tags of course), but I didn't know about the "lang" attribute... According to the General forum FAQ a total of 10 different languages are supported. I should have noticed that by now! Very nice!

Now if support were added for MATLAB/Octave syntax and we had math/LaTeX tags built in, we'd really be cooking with gas...

Share this post


Link to post
Share on other sites
Quote:
Original post by Emergent
...and we had math/LaTeX tags built in, we'd really be cooking with gas...


Yes! I wrote a thread about it in the suggestions forum but never heard from anyone higher up.

Also, sorry for derailing the thread :)

Share this post


Link to post
Share on other sites
AFA the OP:

Looking at the code, you're using the steering mechanism to change which direction the forces from the gas pedal are going, right?

Real cars are more complicated than this, which is why you get the on-ice behavior. Imagine being in a car going at 60. Don't touch the breaks or gas. Now imagine turning. The car will turn. In your model, I don't think it would.

What you need is a "friction ellipse" between the "wheels" and the ground. You change the rotation of this ellipse by turning the wheel. The friction causes the car to change direction as you would expect. I found this which may or may not be useful to you. Basically friction for motion parallel to the tires is quite low, while friction perpendicular to the tires is quite high.

Because of the difficulty of modeling a vehicle properly, most games fake it. You could just record a magnitude for velocity and have the tires determine its direction.

Share this post


Link to post
Share on other sites
Also, as long as I'm whoring out how tags work in the forum:

(a href="http://womewebsiteorother.com")Link description(/a)

Will make a clicky for you to click on. Just replace the () with <>.

And if you see someone else's post with cool tags and you want to know how they did it, just try editing their post like you would one of your own (there's an edit link at the top of every post), and you can see the "source" for their post.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!