• 12
• 10
• 10
• 13
• 10

# Vehicle Dynamics and Physics

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

## 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 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 _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

public function Car()
{

}

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;

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;

wheelBitmap = new Bitmap(wheel);
wheelBitmap.x = -wheelBitmap.width / 2;
wheelBitmap.y = -wheelBitmap.height / 2;

_rightWheel  = new Sprite();
_rightWheel.x = 5
_rightWheel.y = 5;
}

/***********************************************************************************
* 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

switch(_engineStatus)
{
case 0:
//Idle engine
_fTraction.x = 0;
_fTraction.y = 0;
break;
case 1:
//Accelerating

break;
case 2:
//Braking/Reverse
var brakingForce = _intBrakingForce;
if (_intSpeed &lt;= 0) brakingForce = _intReverseForce;

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(); }
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) &lt; _intSteeringAngleMax)
{
_intSteeringAngle = newSteerDirection
}
else
{
$val &gt; 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 &lt; 0.1 && _intSteeringAngle &gt; -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 on other sites
Where are the rear wheels???

##### Share on other sites
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 on other sites
Does anybody have any suggestions??

Cheers
Stu

##### Share on other sites
Quote:
 Original post by stuhowDoes anybody have any suggestions??CheersStu

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 on other sites
Thanks for that, I have modified the post accordingly.

Cheers
Stu

##### Share on other sites
Quote:
 Original post by NumsgilFigure out how to use the source tags. Please. They look like:C++ code goes hereOnly 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 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 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 on other sites
Also, as long as I'm whoring out how tags work in the forum:

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.